<commit_before>#![allow(dead_code)] // until raw_ops are implemented

use libc::c_float;
use libc::c_int;
use libc::c_uchar;
use libc::c_void;
use libc::size_t;
use std::ffi::{CStr, CString};
use std::os::raw::c_void as std_c_void;
use std::ptr;

use crate::eager::{Context, TensorHandle};
use crate::{AnyTensor, DataType, Result, Shape, Status};

use tensorflow_sys as tf;

/// Description of the TensorFlow op to execute.
struct Op {
    inner: *mut tf::TFE_Op,
}
impl_drop!(Op, TFE_DeleteOp);

impl Op {
    fn new(ctx: &Context, op_or_function_name: &str) -> Result<Op> {
        let status = Status::new();

        let op_or_function_name = CString::new(op_or_function_name).unwrap();
        let inner = unsafe { tf::TFE_NewOp(ctx.inner, op_or_function_name.as_ptr(), status.inner) };
        if inner.is_null() {
            return Err(status);
        }
        Ok(Self { inner })
    }

    #[allow(dead_code)]
    fn get_name(&self) -> Result<&str> {
        let status = Status::new();

        let name = unsafe {
            let name = tf::TFE_OpGetName(self.inner, status.inner);
            CStr::from_ptr(name)
        };
        if status.is_ok() {
            return Ok(name.to_str().unwrap());
        }
        Err(status)
    }

    /// Context may not be outlive over the lifetime of `op'
    #[allow(dead_code)]
    fn get_context(&self) -> &Context {
        unimplemented!()
    }

    /// Adds an input to this operation.
    fn add_input(&mut self, input: &TensorHandle) -> Result<()> {
        let status = Status::new();
        unsafe {
            tf::TFE_OpAddInput(self.inner, input.inner, status.inner);
        };
        status.into_result()
    }

    /// Adds multiple inputs to this operation.
    #[allow(dead_code)]
    fn add_input_list(&mut self, inputs: &[TensorHandle]) -> Result<()> {
        let status = Status::new();
        unsafe {
            let mut inputs: Vec<*mut tf::TFE_TensorHandle> =
                inputs.iter().map(|v| v.inner).collect();
            tf::TFE_OpAddInputList(
                self.inner,
                inputs.as_mut_ptr(),
                inputs.len() as c_int,
                status.inner,
            );
        };
        status.into_result()
    }

    /// Sets the value of a string attribute.
    fn set_attr_string(&mut self, attr_name: &str, value: &str) {
        let attr_name = CString::new(attr_name).unwrap();
        let c_value = value.as_bytes();
        unsafe {
            tf::TFE_OpSetAttrString(
                self.inner,
                attr_name.as_ptr(),
                c_value.as_ptr() as *const std_c_void,
                c_value.len() as size_t,
            );
        }
    }

    /// Sets the value of an attribute which holds a list of strings.
    fn set_attr_string_list<S: AsRef<str>>(&mut self, attr_name: &str, values: &[S]) {
        let c_attr_name = CString::new(attr_name).unwrap();
        let bytes: Vec<&[u8]> = values.iter().map(|x| x.as_ref().as_bytes()).collect();
        let ptrs: Vec<*const c_void> = bytes.iter().map(|x| x.as_ptr() as *const c_void).collect();
        let lens: Vec<size_t> = bytes.iter().map(|x| x.len() as size_t).collect();
        unsafe {
            tf::TFE_OpSetAttrStringList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_ptr() as *const *const std_c_void,
                lens.as_ptr(),
                ptrs.len() as c_int,
            );
        }
    }

    /// Sets an int-valued attribute.
    fn set_attr_int(&mut self, attr_name: &str, value: i64) {
        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            tf::TFE_OpSetAttrInt(self.inner, c_attr_name.as_ptr(), value);
        }
    }

    /// Sets an attribute which holds an array of ints.
    fn set_attr_int_list(&mut self, attr_name: &str, value: &[i64]) {
        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            tf::TFE_OpSetAttrIntList(
                self.inner,
                c_attr_name.as_ptr(),
                value.as_ptr(),
                value.len() as i32,
            );
        }
    }

    /// Sets a float-valued attribute.
    fn set_attr_float(&mut self, attr_name: &str, value: f32) {
        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            tf::TFE_OpSetAttrFloat(self.inner, c_attr_name.as_ptr(), value);
        }
    }

    /// Sets an attribute which holds an array of floats.
    fn set_attr_float_list(&mut self, attr_name: &str, value: &[f32]) {
        let c_attr_name = CString::new(attr_name).unwrap();
        // Allow trivial_numeric_casts here because f32 is not necessarily equal to c_float.
        let c_value: Vec<c_float> = value.iter().map(|x| *x as c_float).collect();
        unsafe {
            tf::TFE_OpSetAttrFloatList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
    }

    /// Sets a boolean-valued attribute.
    fn set_attr_bool(&mut self, attr_name: &str, value: bool) {
        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            tf::TFE_OpSetAttrBool(self.inner, c_attr_name.as_ptr(), if value { 1 } else { 0 });
        }
    }

    /// Sets an attribute which holds an array of booleans.
    #[allow(dead_code)]
    fn set_attr_bool_list(&mut self, attr_name: &str, value: &[bool]) {
        let c_attr_name = CString::new(attr_name).unwrap();
        let c_value: Vec<c_uchar> = value.iter().map(|x| if *x { 1 } else { 0 }).collect();
        unsafe {
            tf::TFE_OpSetAttrBoolList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as c_int,
            );
        }
    }

    /// Sets a type-valued attribute.
    fn set_attr_type(&mut self, attr_name: &str, value: DataType) {
        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            tf::TFE_OpSetAttrType(self.inner, c_attr_name.as_ptr(), value.to_c());
        }
    }

    /// Sets an attribute which holds an array of types.
    fn set_attr_type_list(&mut self, attr_name: &str, value: &[DataType]) {
        let c_attr_name = CString::new(attr_name).unwrap();
        let c_value: Vec<tf::TF_DataType> = value.iter().map(|x| x.to_c()).collect();
        unsafe {
            tf::TFE_OpSetAttrTypeList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
    }

    /// Sets a shape-valued attribute.
    fn set_attr_shape(&mut self, attr_name: &str, value: &Shape) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name).unwrap();
        unsafe {
            match value.0 {
                None => tf::TFE_OpSetAttrShape(
                    self.inner,
                    c_attr_name.as_ptr(),
                    ptr::null(),
                    -1,
                    status.inner,
                ),
                Some(ref dims) => {
                    let c_dims: Vec<i64> = dims.iter().map(|x| (*x).unwrap_or(-1)).collect();
                    tf::TFE_OpSetAttrShape(
                        self.inner,
                        c_attr_name.as_ptr(),
                        c_dims.as_ptr(),
                        c_dims.len() as i32,
                        status.inner,
                    );
                }
            }
        }
        status.into_result()
    }

    /// Sets an attribute which holds an array of shapes.
    fn set_attr_shape_list(&mut self, attr_name: &str, value: &[Shape]) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name).unwrap();
        // Convert Option<i64> in each shape to i64 with None becoming -1.
        let c_dims: Vec<Option<Vec<i64>>> = value
            .iter()
            .map(|x| {
                x.0.as_ref()
                    .map(|dims| dims.iter().map(|x| (*x).unwrap_or(-1)).collect())
            })
            .collect();
        let mut ptrs: Vec<*const i64> = c_dims
            .iter()
            .map(|x| match *x {
                None => ptr::null(),
                Some(ref dims) => dims.as_ptr(),
            })
            .collect();
        let lens: Vec<c_int> = value
            .iter()
            .map(|x| match x.0 {
                None => -1,
                Some(ref dims) => dims.len() as c_int,
            })
            .collect();
        unsafe {
            tf::TFE_OpSetAttrShapeList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_mut_ptr(),
                lens.as_ptr(),
                ptrs.len() as c_int,
                status.inner,
            );
        }
        status.into_result()
    }

    /// Sets a tensor-valued attribute.
    fn set_attr_any_tensor(&mut self, attr_name: &str, value: &dyn AnyTensor) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let mut status = Status::new();
        unsafe {
            tf::TFE_OpSetAttrTensor(
                self.inner,
                c_attr_name.as_ptr(),
                value.inner()?,
                status.inner(),
            );
        }
        status.into_result()
    }
}
<commit_msg>remove superfluous unwraps<commit_after>#![allow(dead_code)] // until raw_ops are implemented

use libc::c_float;
use libc::c_int;
use libc::c_uchar;
use libc::c_void;
use libc::size_t;
use std::ffi::{CStr, CString};
use std::os::raw::c_void as std_c_void;
use std::ptr;

use crate::eager::{Context, TensorHandle};
use crate::{AnyTensor, DataType, Result, Shape, Status};

use tensorflow_sys as tf;

/// Description of the TensorFlow op to execute.
struct Op {
    inner: *mut tf::TFE_Op,
}
impl_drop!(Op, TFE_DeleteOp);

impl Op {
    fn new(ctx: &Context, op_or_function_name: &str) -> Result<Op> {
        let status = Status::new();

        let op_or_function_name = CString::new(op_or_function_name)?;
        let inner = unsafe { tf::TFE_NewOp(ctx.inner, op_or_function_name.as_ptr(), status.inner) };
        if inner.is_null() {
            return Err(status);
        }
        Ok(Self { inner })
    }

    #[allow(dead_code)]
    fn get_name(&self) -> Result<&str> {
        let status = Status::new();

        let name = unsafe {
            let name = tf::TFE_OpGetName(self.inner, status.inner);
            CStr::from_ptr(name)
        };
        if status.is_ok() {
            return Ok(name.to_str()?);
        }
        Err(status)
    }

    /// Context may not be outlive over the lifetime of `op'
    #[allow(dead_code)]
    fn get_context(&self) -> &Context {
        unimplemented!()
    }

    /// Adds an input to this operation.
    fn add_input(&mut self, input: &TensorHandle) -> Result<()> {
        let status = Status::new();
        unsafe {
            tf::TFE_OpAddInput(self.inner, input.inner, status.inner);
        };
        status.into_result()
    }

    /// Adds multiple inputs to this operation.
    #[allow(dead_code)]
    fn add_input_list(&mut self, inputs: &[TensorHandle]) -> Result<()> {
        let status = Status::new();
        unsafe {
            let mut inputs: Vec<*mut tf::TFE_TensorHandle> =
                inputs.iter().map(|v| v.inner).collect();
            tf::TFE_OpAddInputList(
                self.inner,
                inputs.as_mut_ptr(),
                inputs.len() as c_int,
                status.inner,
            );
        };
        status.into_result()
    }

    /// Sets the value of a string attribute.
    fn set_attr_string(&mut self, attr_name: &str, value: &str) -> Result<()> {
        let attr_name = CString::new(attr_name)?;
        let c_value = value.as_bytes();
        unsafe {
            tf::TFE_OpSetAttrString(
                self.inner,
                attr_name.as_ptr(),
                c_value.as_ptr() as *const std_c_void,
                c_value.len() as size_t,
            );
        }
        Ok(())
    }

    /// Sets the value of an attribute which holds a list of strings.
    fn set_attr_string_list<S: AsRef<str>>(&mut self, attr_name: &str, values: &[S]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let bytes: Vec<&[u8]> = values.iter().map(|x| x.as_ref().as_bytes()).collect();
        let ptrs: Vec<*const c_void> = bytes.iter().map(|x| x.as_ptr() as *const c_void).collect();
        let lens: Vec<size_t> = bytes.iter().map(|x| x.len() as size_t).collect();
        unsafe {
            tf::TFE_OpSetAttrStringList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_ptr() as *const *const std_c_void,
                lens.as_ptr(),
                ptrs.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets an int-valued attribute.
    fn set_attr_int(&mut self, attr_name: &str, value: i64) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrInt(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of ints.
    fn set_attr_int_list(&mut self, attr_name: &str, value: &[i64]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrIntList(
                self.inner,
                c_attr_name.as_ptr(),
                value.as_ptr(),
                value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a float-valued attribute.
    fn set_attr_float(&mut self, attr_name: &str, value: f32) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrFloat(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of floats.
    fn set_attr_float_list(&mut self, attr_name: &str, value: &[f32]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        // Allow trivial_numeric_casts here because f32 is not necessarily equal to c_float.
        let c_value: Vec<c_float> = value.iter().map(|x| *x as c_float).collect();
        unsafe {
            tf::TFE_OpSetAttrFloatList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a boolean-valued attribute.
    fn set_attr_bool(&mut self, attr_name: &str, value: bool) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrBool(self.inner, c_attr_name.as_ptr(), if value { 1 } else { 0 });
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of booleans.
    fn set_attr_bool_list(&mut self, attr_name: &str, value: &[bool]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<c_uchar> = value.iter().map(|x| if *x { 1 } else { 0 }).collect();
        unsafe {
            tf::TFE_OpSetAttrBoolList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets a type-valued attribute.
    fn set_attr_type(&mut self, attr_name: &str, value: DataType) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrType(self.inner, c_attr_name.as_ptr(), value.to_c());
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of types.
    fn set_attr_type_list(&mut self, attr_name: &str, value: &[DataType]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<tf::TF_DataType> = value.iter().map(|x| x.to_c()).collect();
        unsafe {
            tf::TFE_OpSetAttrTypeList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a shape-valued attribute.
    fn set_attr_shape(&mut self, attr_name: &str, value: &Shape) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            match value.0 {
                None => tf::TFE_OpSetAttrShape(
                    self.inner,
                    c_attr_name.as_ptr(),
                    ptr::null(),
                    -1,
                    status.inner,
                ),
                Some(ref dims) => {
                    let c_dims: Vec<i64> = dims.iter().map(|x| (*x).unwrap_or(-1)).collect();
                    tf::TFE_OpSetAttrShape(
                        self.inner,
                        c_attr_name.as_ptr(),
                        c_dims.as_ptr(),
                        c_dims.len() as i32,
                        status.inner,
                    );
                }
            }
        }
        status.into_result()
    }

    /// Sets an attribute which holds an array of shapes.
    fn set_attr_shape_list(&mut self, attr_name: &str, value: &[Shape]) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        // Convert Option<i64> in each shape to i64 with None becoming -1.
        let c_dims: Vec<Option<Vec<i64>>> = value
            .iter()
            .map(|x| {
                x.0.as_ref()
                    .map(|dims| dims.iter().map(|x| (*x).unwrap_or(-1)).collect())
            })
            .collect();
        let mut ptrs: Vec<*const i64> = c_dims
            .iter()
            .map(|x| match *x {
                None => ptr::null(),
                Some(ref dims) => dims.as_ptr(),
            })
            .collect();
        let lens: Vec<c_int> = value
            .iter()
            .map(|x| match x.0 {
                None => -1,
                Some(ref dims) => dims.len() as c_int,
            })
            .collect();
        unsafe {
            tf::TFE_OpSetAttrShapeList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_mut_ptr(),
                lens.as_ptr(),
                ptrs.len() as c_int,
                status.inner,
            );
        }
        status.into_result()
    }

    /// Sets a tensor-valued attribute.
    fn set_attr_any_tensor(&mut self, attr_name: &str, value: &dyn AnyTensor) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let mut status = Status::new();
        unsafe {
            tf::TFE_OpSetAttrTensor(
                self.inner,
                c_attr_name.as_ptr(),
                value.inner()?,
                status.inner(),
            );
        }
        status.into_result()
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/LZW_compression

use std::hashmap::HashMap;
use std::vec;
use std::str;

fn compress(original_str: &str) -> ~[int] {
   let original = original_str.as_bytes();
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(~[i as u8], i);
   }

   let mut result = ~[];
   let mut w:~[u8] = ~[];
   for &c in original.iter() {
      let mut wc = w.clone();
      wc.push(c);

      match dictionary.find(&wc) {
         Some(_) => w = wc,
         None => {
            result.push(*dictionary.get(&w));
            dictionary.insert(wc, dict_size);
            dict_size += 1;
            w = ~[c];
         }
      }
   }

   if w.len() > 0 {
      result.push(*dictionary.get(&w));
   }

   result
}

fn decompress(compressed: &[int]) -> ~str {
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(i, ~[i as u8]);
   }

   let mut w = ~[compressed[0] as u8];
   let compressed = compressed.slice(1, compressed.len());
   let mut result = w.clone();
   for &k in compressed.iter() {
      let entry =
         match dictionary.find(&k) {
            Some(v) => v.clone(),
            None if k == dict_size => vec::append_one(w.clone(), w[0]),
            None => fail!("Invalid compressed string")
         };

      result = vec::append(result, entry);
      dictionary.insert(dict_size, vec::append_one(w, entry[0]));
      dict_size += 1;
      w = entry;
   }

   str::from_utf8(result)
}

fn main() {
   let original = "TOBEORNOTTOBEORTOBEORNOT";
   let compressed = compress(original);

   for &v in compressed.iter() {
      print!("{} ", v);
   }

   let decompressed = decompress(compressed);
   println(decompressed);

   // Check if the decompressed string corresponds to the original string
   assert!(original == decompressed);
}
<commit_msg>More elegant printing of compressed string<commit_after>// Implements http://rosettacode.org/wiki/LZW_compression

use std::hashmap::HashMap;
use std::vec;
use std::str;

fn compress(original_str: &str) -> ~[int] {
   let original = original_str.as_bytes();
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(~[i as u8], i);
   }

   let mut result = ~[];
   let mut w:~[u8] = ~[];
   for &c in original.iter() {
      let mut wc = w.clone();
      wc.push(c);

      match dictionary.find(&wc) {
         Some(_) => w = wc,
         None => {
            result.push(*dictionary.get(&w));
            dictionary.insert(wc, dict_size);
            dict_size += 1;
            w = ~[c];
         }
      }
   }

   if w.len() > 0 {
      result.push(*dictionary.get(&w));
   }

   result
}

fn decompress(compressed: &[int]) -> ~str {
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(i, ~[i as u8]);
   }

   let mut w = ~[compressed[0] as u8];
   let compressed = compressed.slice(1, compressed.len());
   let mut result = w.clone();
   for &k in compressed.iter() {
      let entry =
         match dictionary.find(&k) {
            Some(v) => v.clone(),
            None if k == dict_size => vec::append_one(w.clone(), w[0]),
            None => fail!("Invalid compressed string")
         };

      result = vec::append(result, entry);
      dictionary.insert(dict_size, vec::append_one(w, entry[0]));
      dict_size += 1;
      w = entry;
   }

   str::from_utf8(result)
}

fn main() {
   let original = "TOBEORNOTTOBEORTOBEORNOT";

   let compressed = compress(original);
   println!("{:?}", compressed);

   let decompressed = decompress(compressed);
   println(decompressed);

   // Check if the decompressed string corresponds to the original string
   assert!(original == decompressed);
}
<|endoftext|>


<commit_before>use codegen::RustWriter;
use std::io;
use std::str;
mod codegen;

struct Grammar {
	rules: ~[~Rule]
}

enum Item {
	Rule
}

struct Rule {
	name: ~str,
	expr: ~Expr,
	ret_type: ~str,
}

enum Attr {
	AttrDefineParser(~str),
	AttrDefineType(~str)
}

struct CharSetCase {
	start: char,
	end: char
}

struct TaggedExpr {
	name: Option<~str>,
	expr: ~Expr
}

enum Expr {
	AnyCharExpr,
	LiteralExpr(~str),
	CharSetExpr(bool, ~[CharSetCase]),
	RuleExpr(~str),
	SequenceExpr(~[~Expr]),
	ChoiceExpr(~[~Expr]),
	OptionalExpr(~Expr),
	ZeroOrMore(~Expr),
	OneOrMore(~Expr),
	DelimitedExpr(~Expr, ~Expr),
	PosAssertExpr(~Expr),
	NegAssertExpr(~Expr),
	StringifyExpr(~Expr),
	ActionExpr(~[TaggedExpr], ~str),
}

fn compile_grammar(w: &RustWriter, grammar: &Grammar) {
	compile_header(w);

	for rule in grammar.rules.iter() {
		compile_rule(w, *rule);
	}
}

fn compile_header(w: &RustWriter) {
	w.write("// Generated by rust-peg. Do not edit.
extern mod std;
use std::str::{CharRange};

#[inline]
fn slice_eq(input: &str, pos: uint, m: &str) -> Result<(uint, ()), uint> {
    let l = m.len();
    if (input.len() >= pos + l && input.slice(pos, pos+l) == m) {
        Ok((pos+l, ()))
    } else {
        Err(pos)
    }
}

#[inline]
fn any_char(input: &str, pos: uint) -> Result<(uint, ()), uint> {
    if input.len() > pos {
        Ok((input.char_range_at(pos).next, ()))
    } else {
        Err(pos)
    }
}
");
}

fn compile_rule(w: &RustWriter, rule: &Rule) {
	do w.def_fn(false, "parse_"+rule.name, "input: &str, pos: uint", "Result<(uint, " + rule.ret_type + ") , uint>") {
		compile_expr(w, rule.expr);
	}

	do w.def_fn(true, rule.name, "input: &str", "Result<"+rule.ret_type+", ~str>") {
		do w.match_block("parse_"+rule.name+"(input, 0)") {
			do w.match_case("Ok((pos, value))") {
				w.if_else("pos == input.len()",
					|| { w.line("Ok(value)"); },
					|| { w.line("Err(~\"Unexpected characters at end of input\")"); }
				)
			}
			w.match_inline_case("Err(pos)", "Err(\"Error at \"+ pos.to_str())");
		}
	}
}

fn compile_match_and_then(w: &RustWriter, e: &Expr, value_name: &str, then: &fn()) {
	do w.let_block("seq_res") {
		compile_expr(w, e);
	}
	do w.match_block("seq_res") {
		w.match_inline_case("Err(pos)", "Err(pos)");
		do w.match_case("Ok((pos, "+value_name+"))") {
			then();
		}
	}
}

fn compile_zero_or_more(w: &RustWriter, e: &Expr, list_initial: &str) {
	w.let_mut_stmt("repeat_pos", "pos");
	w.let_mut_stmt("repeat_value", list_initial);
	do w.loop_block {
		do w.let_block("step_res") {
			w.let_stmt("pos", "repeat_pos");
			compile_expr(w, e);
		}
		do w.match_block("step_res") {
			do w.match_case("Ok((newpos, value))") {
				w.line("repeat_pos = newpos;");
				w.line("repeat_value.push(value);")
			}
			do w.match_case("Err(*)") {
				w.line("break;");
			}
		}
	}
	w.line("Ok((repeat_pos, repeat_value))");
}

fn compile_expr(w: &RustWriter, e: &Expr) {
	match *e {
		AnyCharExpr => {
			w.line("any_char(input, pos)");
			/*w.if_else("input.len() > pos",
				||{ w.line("Ok(pos+1)"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		LiteralExpr(ref s) => {
			w.line("slice_eq(input, pos, \""+*s+"\")");
			/*w.if_else("slice_eq(input, pos, \""+*s+"\")",
				||{ w.line("Ok(pos+" + s.len().to_str() + ")"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		CharSetExpr(invert, ref cases) => {
			let result_strs = ("Ok((next, ()))", "Err(pos)");
			let (y_str, n_str) = if !invert { result_strs } else { result_strs.swap() };

			w.if_else("input.len() > pos",
				|| {
					w.line("let CharRange {ch, next} = input.char_range_at(pos);");
					do w.match_block("ch") {
						w.write_indent();
						for (i, case) in cases.iter().enumerate() {
							if i != 0 { w.write(" | "); }
							if case.start == case.end {
								w.write("'"+str::from_char(case.start)+"'");
							} else {
								w.write("'"+str::from_char(case.start)+"'..'"+str::from_char(case.end)+"'");
							}
						}
						w.write(" => { "+y_str+" }\n");
						w.match_inline_case("_", n_str);
					}
				},
				|| { w.line("Err(pos)"); }
			)
		}

		RuleExpr(ref ruleName) => {
			w.line("parse_"+*ruleName+"(input, pos)");
		}

		SequenceExpr(ref exprs) => {
			fn write_seq(w: &RustWriter, exprs: &[~Expr]) {
				if (exprs.len() == 1) {
					compile_expr(w, exprs[0]);
				} else {
					do compile_match_and_then(w, exprs[0], "_") {
						write_seq(w, exprs.tail());
					}
				}
			}

			if (exprs.len() > 0 ) {
				write_seq(w, *exprs);
			}
		}

		ChoiceExpr(ref exprs) => {
			fn write_choice(w: &RustWriter, exprs: &[~Expr]) {
				if (exprs.len() == 1) {
					compile_expr(w, exprs[0]);
				} else {
					do w.let_block("choice_res") {
						compile_expr(w, exprs[0]);
					}
					do w.match_block("choice_res") {
						w.match_inline_case("Ok((pos, value))", "Ok((pos, value))");
						do w.match_case("Err(*)") {
							write_choice(w, exprs.tail());
						}
					}
				}
			}

			if (exprs.len() > 0 ) {
				write_choice(w, *exprs);
			}
		}

		OptionalExpr(ref e) => {
			do w.let_block("optional_res") {
				compile_expr(w, *e);
			}
			do w.match_block("optional_res") {
				w.match_inline_case("Ok((newpos, value))", "Ok((newpos, Some(value)))");
				w.match_inline_case("Err(*)", "Ok((pos, None))");
			}
		}

		ZeroOrMore(ref e) => {
			compile_zero_or_more(w, *e, "~[]");
		}

		OneOrMore(ref e) => {
			do compile_match_and_then(w, *e, "first_value") {
				compile_zero_or_more(w, *e, "~[first_value]");
			}
		}

		DelimitedExpr(_, _) => fail!("not implemented"),
		StringifyExpr(*) => fail!("not implemented"),

		PosAssertExpr(ref e) => {
			do w.let_block("assert_res") {
				compile_expr(w, *e);
			}
			do w.match_block("assert_res") {
				w.match_inline_case("Ok(*)", "Ok((pos, ()))");
				w.match_inline_case("Err(*)", "Err(pos)");
			}
		}

		NegAssertExpr(ref e) => {
			do w.let_block("neg_assert_res") {
				compile_expr(w, *e);
			}
			do w.match_block("neg_assert_res") {
				w.match_inline_case("Err(*)", "Ok((pos, ()))");
				w.match_inline_case("Ok(*)", "Err(pos)");
			}
		}

		ActionExpr(ref exprs, ref code) => {
			w.let_stmt("start_pos", "pos");
			fn write_seq(w: &RustWriter, exprs: &[TaggedExpr], code: &str) {
				if (exprs.len() > 0) {
					let name = match exprs.head().name {
						Some(ref s) => s.as_slice(),
						None => "_"
					};
					do compile_match_and_then(w, exprs.head().expr, name) {
						write_seq(w, exprs.tail(), code);
					}
				} else {
					w.write_indent();
					w.write("Ok((pos, (|| {");
					w.write(code);
					w.write("})()))\n");
				}
			}

			write_seq(w, *exprs, *code);
		}
	}
}

fn main() {
	let grammar = include!("grammar_def.rs");
	let w = RustWriter::new(io::stdout());
	compile_grammar(&w, grammar);
}<commit_msg>Don't compile result value if not used<commit_after>use codegen::RustWriter;
use std::io;
use std::str;
mod codegen;

struct Grammar {
	rules: ~[~Rule]
}

enum Item {
	Rule
}

struct Rule {
	name: ~str,
	expr: ~Expr,
	ret_type: ~str,
}

enum Attr {
	AttrDefineParser(~str),
	AttrDefineType(~str)
}

struct CharSetCase {
	start: char,
	end: char
}

struct TaggedExpr {
	name: Option<~str>,
	expr: ~Expr
}

enum Expr {
	AnyCharExpr,
	LiteralExpr(~str),
	CharSetExpr(bool, ~[CharSetCase]),
	RuleExpr(~str),
	SequenceExpr(~[~Expr]),
	ChoiceExpr(~[~Expr]),
	OptionalExpr(~Expr),
	ZeroOrMore(~Expr),
	OneOrMore(~Expr),
	DelimitedExpr(~Expr, ~Expr),
	PosAssertExpr(~Expr),
	NegAssertExpr(~Expr),
	StringifyExpr(~Expr),
	ActionExpr(~[TaggedExpr], ~str),
}

fn compile_grammar(w: &RustWriter, grammar: &Grammar) {
	compile_header(w);

	for rule in grammar.rules.iter() {
		compile_rule(w, *rule);
	}
}

fn compile_header(w: &RustWriter) {
	w.write("// Generated by rust-peg. Do not edit.
extern mod std;
use std::str::{CharRange};

#[inline]
fn slice_eq(input: &str, pos: uint, m: &str) -> Result<(uint, ()), uint> {
    let l = m.len();
    if (input.len() >= pos + l && input.slice(pos, pos+l) == m) {
        Ok((pos+l, ()))
    } else {
        Err(pos)
    }
}

#[inline]
fn any_char(input: &str, pos: uint) -> Result<(uint, ()), uint> {
    if input.len() > pos {
        Ok((input.char_range_at(pos).next, ()))
    } else {
        Err(pos)
    }
}
");
}

fn compile_rule(w: &RustWriter, rule: &Rule) {
	do w.def_fn(false, "parse_"+rule.name, "input: &str, pos: uint", "Result<(uint, " + rule.ret_type + ") , uint>") {
		compile_expr(w, rule.expr, rule.ret_type != ~"()");
	}

	do w.def_fn(true, rule.name, "input: &str", "Result<"+rule.ret_type+", ~str>") {
		do w.match_block("parse_"+rule.name+"(input, 0)") {
			do w.match_case("Ok((pos, value))") {
				w.if_else("pos == input.len()",
					|| { w.line("Ok(value)"); },
					|| { w.line("Err(~\"Unexpected characters at end of input\")"); }
				)
			}
			w.match_inline_case("Err(pos)", "Err(\"Error at \"+ pos.to_str())");
		}
	}
}

fn compile_match_and_then(w: &RustWriter, e: &Expr, value_name: Option<&str>, then: &fn()) {
	do w.let_block("seq_res") {
		compile_expr(w, e, value_name.is_some());
	}
	do w.match_block("seq_res") {
		w.match_inline_case("Err(pos)", "Err(pos)");
		do w.match_case("Ok((pos, "+value_name.unwrap_or_default("_")+"))") {
			then();
		}
	}
}

fn compile_zero_or_more(w: &RustWriter, e: &Expr, list_initial: Option<&str>) {
	w.let_mut_stmt("repeat_pos", "pos");
	let result_used = list_initial.is_some();
	if (result_used) {
		w.let_mut_stmt("repeat_value", list_initial.unwrap());
	}
	do w.loop_block {
		do w.let_block("step_res") {
			w.let_stmt("pos", "repeat_pos");
			compile_expr(w, e, result_used);
		}
		do w.match_block("step_res") {
			let match_arm = if result_used {
				"Ok((newpos, value))"
			} else {
				"Ok((newpos, _))"
			};
			do w.match_case(match_arm) {
				w.line("repeat_pos = newpos;");
				if result_used {
					w.line("repeat_value.push(value);");
				}
			}
			do w.match_case("Err(*)") {
				w.line("break;");
			}
		}
	}
	if result_used {
		w.line("Ok((repeat_pos, repeat_value))");
	} else {
		w.line("Ok((repeat_pos, ()))");
	}
}

fn compile_expr(w: &RustWriter, e: &Expr, result_used: bool) {
	match *e {
		AnyCharExpr => {
			w.line("any_char(input, pos)");
			/*w.if_else("input.len() > pos",
				||{ w.line("Ok(pos+1)"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		LiteralExpr(ref s) => {
			w.line("slice_eq(input, pos, \""+*s+"\")");
			/*w.if_else("slice_eq(input, pos, \""+*s+"\")",
				||{ w.line("Ok(pos+" + s.len().to_str() + ")"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		CharSetExpr(invert, ref cases) => {
			let result_strs = ("Ok((next, ()))", "Err(pos)");
			let (y_str, n_str) = if !invert { result_strs } else { result_strs.swap() };

			w.if_else("input.len() > pos",
				|| {
					w.line("let CharRange {ch, next} = input.char_range_at(pos);");
					do w.match_block("ch") {
						w.write_indent();
						for (i, case) in cases.iter().enumerate() {
							if i != 0 { w.write(" | "); }
							if case.start == case.end {
								w.write("'"+str::from_char(case.start)+"'");
							} else {
								w.write("'"+str::from_char(case.start)+"'..'"+str::from_char(case.end)+"'");
							}
						}
						w.write(" => { "+y_str+" }\n");
						w.match_inline_case("_", n_str);
					}
				},
				|| { w.line("Err(pos)"); }
			)
		}

		RuleExpr(ref ruleName) => {
			w.line("parse_"+*ruleName+"(input, pos)");
		}

		SequenceExpr(ref exprs) => {
			fn write_seq(w: &RustWriter, exprs: &[~Expr]) {
				if (exprs.len() == 1) {
					compile_expr(w, exprs[0], false);
				} else {
					do compile_match_and_then(w, exprs[0], None) {
						write_seq(w, exprs.tail());
					}
				}
			}

			if (exprs.len() > 0 ) {
				write_seq(w, *exprs);
			}
		}

		ChoiceExpr(ref exprs) => {
			fn write_choice(w: &RustWriter, exprs: &[~Expr], result_used: bool) {
				if (exprs.len() == 1) {
					compile_expr(w, exprs[0], result_used);
				} else {
					do w.let_block("choice_res") {
						compile_expr(w, exprs[0], result_used);
					}
					do w.match_block("choice_res") {
						w.match_inline_case("Ok((pos, value))", "Ok((pos, value))");
						do w.match_case("Err(*)") {
							write_choice(w, exprs.tail(), result_used);
						}
					}
				}
			}

			if (exprs.len() > 0 ) {
				write_choice(w, *exprs, result_used);
			}
		}

		OptionalExpr(ref e) => {
			do w.let_block("optional_res") {
				compile_expr(w, *e, result_used);
			}
			do w.match_block("optional_res") {
				w.match_inline_case("Ok((newpos, value))", "Ok((newpos, Some(value)))");
				w.match_inline_case("Err(*)", "Ok((pos, None))");
			}
		}

		ZeroOrMore(ref e) => {
			compile_zero_or_more(w, *e, if result_used { Some("~[]") } else { None });
		}

		OneOrMore(ref e) => {
			do compile_match_and_then(w, *e, if result_used { Some("first_value") } else { None }) {
				compile_zero_or_more(w, *e, if result_used { Some("~[first_value]") } else { None });
			}
		}

		DelimitedExpr(_, _) => fail!("not implemented"),
		StringifyExpr(*) => fail!("not implemented"),

		PosAssertExpr(ref e) => {
			do w.let_block("assert_res") {
				compile_expr(w, *e, false);
			}
			do w.match_block("assert_res") {
				w.match_inline_case("Ok(*)", "Ok((pos, ()))");
				w.match_inline_case("Err(*)", "Err(pos)");
			}
		}

		NegAssertExpr(ref e) => {
			do w.let_block("neg_assert_res") {
				compile_expr(w, *e, false);
			}
			do w.match_block("neg_assert_res") {
				w.match_inline_case("Err(*)", "Ok((pos, ()))");
				w.match_inline_case("Ok(*)", "Err(pos)");
			}
		}

		ActionExpr(ref exprs, ref code) => {
			w.let_stmt("start_pos", "pos");
			fn write_seq(w: &RustWriter, exprs: &[TaggedExpr], code: &str) {
				if (exprs.len() > 0) {
					let name = exprs.head().name.map(|s| s.as_slice());
					do compile_match_and_then(w, exprs.head().expr, name) {
						write_seq(w, exprs.tail(), code);
					}
				} else {
					w.write_indent();
					w.write("Ok((pos, (|| {");
					w.write(code);
					w.write("})()))\n");
				}
			}

			write_seq(w, *exprs, *code);
		}
	}
}

fn main() {
	let grammar = include!("grammar_def.rs");
	let w = RustWriter::new(io::stdout());
	compile_grammar(&w, grammar);
}<|endoftext|>


<commit_before>use std::ptr;
use std::hash::{Hash, Hasher};
use std::slice::Iter as SliceIter;
use std::iter::Zip as ZipIter;
use std::iter::Map as MapIter;
use std::iter::Enumerate;
use std::option::IntoIter as OptionIntoIter;
use std::iter::Cycle;

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Coordinates(pub usize, pub usize);

impl Coordinates {
    pub fn in_direction(&self, direction: Direction) -> Option<Coordinates> {
        match direction {
            Direction::Up if self.1 > 0 => Some(Coordinates(self.0, self.1 - 1)),
            Direction::Right if self.0 < usize::max_value() => Some(
                Coordinates(self.0 + 1, self.1),
            ),
            Direction::Down if self.1 < usize::max_value() => Some(Coordinates(self.0, self.1 + 1)),
            Direction::Left if self.0 > 0 => Some(Coordinates(self.0 - 1, self.1)),
            _ => None,
        }
    }

    pub fn direction_to(&self, to: Coordinates) -> Option<Direction> {
        if self.0 == to.0 && self.1 == to.1 {
            return None
        }

        Some(if to.1 + to.0 >= self.1 + self.0 && to.1 + self.0 > to.0 + self.1 {
            Direction::Down
        } else if to.1 + self.0 <= to.0 + self.1 && to.1 + to.0 > self.1 + self.0 {
            Direction::Right
        } else if to.1 + to.0 <= self.1 + self.0 && to.1 + self.0 < to.0 + self.1 {
            Direction::Up
        } else {
            Direction::Left
        })
    }
}

#[test]
fn in_direction_overflow() {
    assert!(Coordinates(0, 0).in_direction(Direction::Up).is_none());
    assert!(Coordinates(0, 0).in_direction(Direction::Left).is_none());
    assert!(Coordinates(0, 0).in_direction(Direction::Down).is_some());
    assert!(Coordinates(0, 0).in_direction(Direction::Right).is_some());

    assert!(Coordinates(1, 1).in_direction(Direction::Up).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Left).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Down).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Right).is_some());

    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Up)
            .is_some()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Left)
            .is_some()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Down)
            .is_none()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Right)
            .is_none()
    );
}

#[test]
fn test_direction_to() {
    assert_eq!(Coordinates(1, 1).direction_to(Coordinates(1, 1)), None);

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(1, 0)), Some(Direction::Right));
    assert_eq!(Coordinates(2, 0).direction_to(Coordinates(1, 0)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(0, 1)), Some(Direction::Up));
    assert_eq!(Coordinates(0, 2).direction_to(Coordinates(0, 1)), Some(Direction::Down));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(2, 1)), Some(Direction::Right));
    assert_eq!(Coordinates(4, 0).direction_to(Coordinates(2, 1)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 2).direction_to(Coordinates(2, 1)), Some(Direction::Right));
    assert_eq!(Coordinates(4, 2).direction_to(Coordinates(2, 1)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(1, 2)), Some(Direction::Up));
    assert_eq!(Coordinates(0, 4).direction_to(Coordinates(1, 2)), Some(Direction::Down));
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Direction {
    Up,
    Right,
    Down,
    Left,
}

impl Direction {
    fn clockwise() -> DirectionClockwiseIter {
        DirectionClockwiseIter { direction: Some(Direction::Up) }
    }
}

#[derive(Debug)]
pub struct DirectionClockwiseIter {
    direction: Option<Direction>,
}

impl Iterator for DirectionClockwiseIter {
    type Item = Direction;

    fn next(&mut self) -> Option<Direction> {
        let next_direction = match self.direction {
            Some(Direction::Up) => Some(Direction::Right),
            Some(Direction::Right) => Some(Direction::Down),
            Some(Direction::Down) => Some(Direction::Left),
            Some(Direction::Left) => None,
            None => None,
        };
        let ret = self.direction;
        self.direction = next_direction;
        ret
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Location<'m> {
    map: &'m Map,
    pub coordinates: Coordinates,
    pub tile: &'m Tile,
}

impl<'m> PartialEq for Location<'m> {
    fn eq(&self, other: &Location<'m>) -> bool {
        ptr::eq(self.tile, other.tile)
    }
}

impl<'m> Eq for Location<'m> {}

impl<'m> Hash for Location<'m> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize((self.tile as *const Tile) as usize)
    }
}

impl<'m> Location<'m> {
    pub fn neighbours(&self) -> NeighboursIter<'m> {
        NeighboursIter {
            location: self.clone(),
            directions: Direction::clockwise(),
        }
    }

    pub fn in_direction(&self, direction: Direction) -> Option<Location<'m>> {
        self.coordinates.in_direction(direction).and_then(
            |coordinates| {
                self.map.location(coordinates)
            },
        )
    }

    pub fn direction_to(&self, to: Location<'m>) -> Option<Direction> {
        self.coordinates.direction_to(to.coordinates)
    }

    pub fn walkable(&self) -> bool {
        match *self.tile {
            Tile::Empty => true,
            _ => false,
        }
    }
}

pub struct NeighboursIter<'m> {
    location: Location<'m>,
    directions: DirectionClockwiseIter,
}

impl<'m> Iterator for NeighboursIter<'m> {
    type Item = (Direction, Location<'m>);

    fn next(&mut self) -> Option<(Direction, Location<'m>)> {
        while let Some(direction) = self.directions.next() {
            if let ret @ Some(_) = self.location.in_direction(direction).map(|location| {
                (direction, location)
            })
            {
                return ret;
            }
        }
        None
    }
}

#[test]
fn location_neighbours() {
    let map = Map::new(Dimension::new(8).unwrap(), Dimension::new(8).unwrap());

    assert_eq!(
        map.location(Coordinates(0, 0))
            .unwrap()
            .neighbours()
            .collect::<Vec<_>>(),
        vec![
            (Direction::Right, map.location(Coordinates(1, 0)).unwrap()),
            (Direction::Down, map.location(Coordinates(0, 1)).unwrap()),
        ]
    )
}

#[derive(PartialEq, Eq, Hash, Debug)]
pub enum Tile {
    Empty,
    Wall,
}

#[derive(Debug)]
pub struct Map {
    tiles: Vec<Vec<Tile>>, // TODO: Matix
}

pub struct Dimension(usize);

impl Dimension {
    pub fn new(dimension: usize) -> Option<Dimension> {
        if dimension > 0 {
            Some(Dimension(dimension))
        } else {
            None
        }
    }

    pub fn unwrap(self) -> usize {
        self.0
    }
}

impl Map {
    pub fn new(width: Dimension, height: Dimension) -> Map {
        let width = width.unwrap();
        let height = height.unwrap();

        Map {
            tiles: (0..height)
                .map(|_row| (0..width).map(|_col| Tile::Empty).collect())
                .collect(),
        }
    }

    pub fn width(&self) -> usize {
        self.tiles.iter().next().unwrap().len()
    }

    pub fn height(&self) -> usize {
        self.tiles.len()
    }

    pub fn get_mut_tile(&mut self, coordinates: Coordinates) -> Option<&mut Tile> {
        self.tiles.get_mut(coordinates.1).and_then(|row| {
            row.get_mut(coordinates.0)
        })
    }

    pub fn location(&self, coordinates: Coordinates) -> Option<Location> {
        self.tiles
            .get(coordinates.1)
            .and_then(|row| row.get(coordinates.0))
            .map(|tile| {
                Location {
                    map: &self,
                    coordinates: coordinates,
                    tile: tile,
                }
            })
    }

    pub fn rows(&self) -> RowIter {
        fn to_row<'m>((row_no, (tiles, map)): (usize, (&'m Vec<Tile>, &'m Map))) -> Row<'m> {
            Row {
                map: map,
                row_no: row_no,
                tiles: tiles.as_slice(),
            }
        }
        let maps = Some(self).into_iter().cycle();
        RowIter(self.tiles.iter().zip(maps).enumerate().map(to_row))
    }
}

pub struct Row<'m> {
    map: &'m Map,
    pub row_no: usize,
    pub tiles: &'m [Tile],
}

impl<'m> IntoIterator for Row<'m> {
    type Item = Location<'m>;
    type IntoIter = RowLocationsIter<'m>;

    fn into_iter(self) -> RowLocationsIter<'m> {
        let maps = Some(self.map).into_iter().cycle();
        RowLocationsIter {
            row_no: self.row_no,
            row_iter: self.tiles.iter().zip(maps).enumerate(),
        }
    }
}

type ESIter<'i, T> = Enumerate<ZipIter<SliceIter<'i, T>, Cycle<OptionIntoIter<&'i Map>>>>;
type ToRowFn<'m> = fn((usize, (&'m Vec<Tile>, &'m Map))) -> Row<'m>;
pub struct RowIter<'m>(MapIter<ESIter<'m, Vec<Tile>>, ToRowFn<'m>>);

impl<'m> Iterator for RowIter<'m> {
    type Item = Row<'m>;

    fn next(&mut self) -> Option<Row<'m>> {
        self.0.next()
    }
}

pub struct RowLocationsIter<'m> {
    row_no: usize,
    row_iter: ESIter<'m, Tile>,
}

impl<'m> Iterator for RowLocationsIter<'m> {
    type Item = Location<'m>;

    fn next(&mut self) -> Option<Location<'m>> {
        self.row_iter.next().map(|(col_no, (tile, map))| {
            Location {
                map: map,
                coordinates: Coordinates(col_no, self.row_no),
                tile: tile,
            }
        })
    }
}

#[test]
fn test_direction_iter() {
    assert_eq!(
        Direction::clockwise().collect::<Vec<_>>(),
        vec![
            Direction::Up,
            Direction::Right,
            Direction::Down,
            Direction::Left,
        ]
    )
}
<commit_msg>fixed test<commit_after>use std::ptr;
use std::hash::{Hash, Hasher};
use std::slice::Iter as SliceIter;
use std::iter::Zip as ZipIter;
use std::iter::Map as MapIter;
use std::iter::Enumerate;
use std::option::IntoIter as OptionIntoIter;
use std::iter::Cycle;

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Coordinates(pub usize, pub usize);

impl Coordinates {
    pub fn in_direction(&self, direction: Direction) -> Option<Coordinates> {
        match direction {
            Direction::Up if self.1 > 0 => Some(Coordinates(self.0, self.1 - 1)),
            Direction::Right if self.0 < usize::max_value() => Some(
                Coordinates(self.0 + 1, self.1),
            ),
            Direction::Down if self.1 < usize::max_value() => Some(Coordinates(self.0, self.1 + 1)),
            Direction::Left if self.0 > 0 => Some(Coordinates(self.0 - 1, self.1)),
            _ => None,
        }
    }

    pub fn direction_to(&self, to: Coordinates) -> Option<Direction> {
        if self.0 == to.0 && self.1 == to.1 {
            return None
        }

        Some(if to.1 + to.0 >= self.1 + self.0 && to.1 + self.0 > to.0 + self.1 {
            Direction::Down
        } else if to.1 + self.0 <= to.0 + self.1 && to.1 + to.0 > self.1 + self.0 {
            Direction::Right
        } else if to.1 + to.0 <= self.1 + self.0 && to.1 + self.0 < to.0 + self.1 {
            Direction::Up
        } else {
            Direction::Left
        })
    }
}

#[test]
fn in_direction_overflow() {
    assert!(Coordinates(0, 0).in_direction(Direction::Up).is_none());
    assert!(Coordinates(0, 0).in_direction(Direction::Left).is_none());
    assert!(Coordinates(0, 0).in_direction(Direction::Down).is_some());
    assert!(Coordinates(0, 0).in_direction(Direction::Right).is_some());

    assert!(Coordinates(1, 1).in_direction(Direction::Up).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Left).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Down).is_some());
    assert!(Coordinates(1, 1).in_direction(Direction::Right).is_some());

    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Up)
            .is_some()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Left)
            .is_some()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Down)
            .is_none()
    );
    assert!(
        Coordinates(usize::max_value(), usize::max_value())
            .in_direction(Direction::Right)
            .is_none()
    );
}

#[test]
fn test_direction_to() {
    assert_eq!(Coordinates(1, 1).direction_to(Coordinates(1, 1)), None);

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(1, 0)), Some(Direction::Right));
    assert_eq!(Coordinates(2, 0).direction_to(Coordinates(1, 0)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(0, 1)), Some(Direction::Down));
    assert_eq!(Coordinates(0, 2).direction_to(Coordinates(0, 1)), Some(Direction::Up));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(2, 1)), Some(Direction::Right));
    assert_eq!(Coordinates(4, 0).direction_to(Coordinates(2, 1)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 2).direction_to(Coordinates(2, 1)), Some(Direction::Right));
    assert_eq!(Coordinates(4, 2).direction_to(Coordinates(2, 1)), Some(Direction::Left));

    assert_eq!(Coordinates(0, 0).direction_to(Coordinates(1, 2)), Some(Direction::Down));
    assert_eq!(Coordinates(0, 4).direction_to(Coordinates(1, 2)), Some(Direction::Up));
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Direction {
    Up,
    Right,
    Down,
    Left,
}

impl Direction {
    fn clockwise() -> DirectionClockwiseIter {
        DirectionClockwiseIter { direction: Some(Direction::Up) }
    }
}

#[derive(Debug)]
pub struct DirectionClockwiseIter {
    direction: Option<Direction>,
}

impl Iterator for DirectionClockwiseIter {
    type Item = Direction;

    fn next(&mut self) -> Option<Direction> {
        let next_direction = match self.direction {
            Some(Direction::Up) => Some(Direction::Right),
            Some(Direction::Right) => Some(Direction::Down),
            Some(Direction::Down) => Some(Direction::Left),
            Some(Direction::Left) => None,
            None => None,
        };
        let ret = self.direction;
        self.direction = next_direction;
        ret
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Location<'m> {
    map: &'m Map,
    pub coordinates: Coordinates,
    pub tile: &'m Tile,
}

impl<'m> PartialEq for Location<'m> {
    fn eq(&self, other: &Location<'m>) -> bool {
        ptr::eq(self.tile, other.tile)
    }
}

impl<'m> Eq for Location<'m> {}

impl<'m> Hash for Location<'m> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize((self.tile as *const Tile) as usize)
    }
}

impl<'m> Location<'m> {
    pub fn neighbours(&self) -> NeighboursIter<'m> {
        NeighboursIter {
            location: self.clone(),
            directions: Direction::clockwise(),
        }
    }

    pub fn in_direction(&self, direction: Direction) -> Option<Location<'m>> {
        self.coordinates.in_direction(direction).and_then(
            |coordinates| {
                self.map.location(coordinates)
            },
        )
    }

    pub fn direction_to(&self, to: Location<'m>) -> Option<Direction> {
        self.coordinates.direction_to(to.coordinates)
    }

    pub fn walkable(&self) -> bool {
        match *self.tile {
            Tile::Empty => true,
            _ => false,
        }
    }
}

pub struct NeighboursIter<'m> {
    location: Location<'m>,
    directions: DirectionClockwiseIter,
}

impl<'m> Iterator for NeighboursIter<'m> {
    type Item = (Direction, Location<'m>);

    fn next(&mut self) -> Option<(Direction, Location<'m>)> {
        while let Some(direction) = self.directions.next() {
            if let ret @ Some(_) = self.location.in_direction(direction).map(|location| {
                (direction, location)
            })
            {
                return ret;
            }
        }
        None
    }
}

#[test]
fn location_neighbours() {
    let map = Map::new(Dimension::new(8).unwrap(), Dimension::new(8).unwrap());

    assert_eq!(
        map.location(Coordinates(0, 0))
            .unwrap()
            .neighbours()
            .collect::<Vec<_>>(),
        vec![
            (Direction::Right, map.location(Coordinates(1, 0)).unwrap()),
            (Direction::Down, map.location(Coordinates(0, 1)).unwrap()),
        ]
    )
}

#[derive(PartialEq, Eq, Hash, Debug)]
pub enum Tile {
    Empty,
    Wall,
}

#[derive(Debug)]
pub struct Map {
    tiles: Vec<Vec<Tile>>, // TODO: Matix
}

pub struct Dimension(usize);

impl Dimension {
    pub fn new(dimension: usize) -> Option<Dimension> {
        if dimension > 0 {
            Some(Dimension(dimension))
        } else {
            None
        }
    }

    pub fn unwrap(self) -> usize {
        self.0
    }
}

impl Map {
    pub fn new(width: Dimension, height: Dimension) -> Map {
        let width = width.unwrap();
        let height = height.unwrap();

        Map {
            tiles: (0..height)
                .map(|_row| (0..width).map(|_col| Tile::Empty).collect())
                .collect(),
        }
    }

    pub fn width(&self) -> usize {
        self.tiles.iter().next().unwrap().len()
    }

    pub fn height(&self) -> usize {
        self.tiles.len()
    }

    pub fn get_mut_tile(&mut self, coordinates: Coordinates) -> Option<&mut Tile> {
        self.tiles.get_mut(coordinates.1).and_then(|row| {
            row.get_mut(coordinates.0)
        })
    }

    pub fn location(&self, coordinates: Coordinates) -> Option<Location> {
        self.tiles
            .get(coordinates.1)
            .and_then(|row| row.get(coordinates.0))
            .map(|tile| {
                Location {
                    map: &self,
                    coordinates: coordinates,
                    tile: tile,
                }
            })
    }

    pub fn rows(&self) -> RowIter {
        fn to_row<'m>((row_no, (tiles, map)): (usize, (&'m Vec<Tile>, &'m Map))) -> Row<'m> {
            Row {
                map: map,
                row_no: row_no,
                tiles: tiles.as_slice(),
            }
        }
        let maps = Some(self).into_iter().cycle();
        RowIter(self.tiles.iter().zip(maps).enumerate().map(to_row))
    }
}

pub struct Row<'m> {
    map: &'m Map,
    pub row_no: usize,
    pub tiles: &'m [Tile],
}

impl<'m> IntoIterator for Row<'m> {
    type Item = Location<'m>;
    type IntoIter = RowLocationsIter<'m>;

    fn into_iter(self) -> RowLocationsIter<'m> {
        let maps = Some(self.map).into_iter().cycle();
        RowLocationsIter {
            row_no: self.row_no,
            row_iter: self.tiles.iter().zip(maps).enumerate(),
        }
    }
}

type ESIter<'i, T> = Enumerate<ZipIter<SliceIter<'i, T>, Cycle<OptionIntoIter<&'i Map>>>>;
type ToRowFn<'m> = fn((usize, (&'m Vec<Tile>, &'m Map))) -> Row<'m>;
pub struct RowIter<'m>(MapIter<ESIter<'m, Vec<Tile>>, ToRowFn<'m>>);

impl<'m> Iterator for RowIter<'m> {
    type Item = Row<'m>;

    fn next(&mut self) -> Option<Row<'m>> {
        self.0.next()
    }
}

pub struct RowLocationsIter<'m> {
    row_no: usize,
    row_iter: ESIter<'m, Tile>,
}

impl<'m> Iterator for RowLocationsIter<'m> {
    type Item = Location<'m>;

    fn next(&mut self) -> Option<Location<'m>> {
        self.row_iter.next().map(|(col_no, (tile, map))| {
            Location {
                map: map,
                coordinates: Coordinates(col_no, self.row_no),
                tile: tile,
            }
        })
    }
}

#[test]
fn test_direction_iter() {
    assert_eq!(
        Direction::clockwise().collect::<Vec<_>>(),
        vec![
            Direction::Up,
            Direction::Right,
            Direction::Down,
            Direction::Left,
        ]
    )
}
<|endoftext|>


<commit_before>// This module provides the main structures and mechanics of the game

/// There are two players playing the match: Light and Dark
#[derive(Clone, Copy, PartialEq)]
pub enum Player {
    Light,
    Dark,
}

impl Player {
    /// Get the player of the opposite kind to self
    fn opposite(&self) -> Player {
        match *self {
            Player::Light => {
                Player::Dark
                    }
            Player::Dark => {
                Player::Light
            }
        }
    }
}

/// A game can be in two status: either running (with a next player to play) or ended.
#[derive(Clone, Copy)]
pub enum Status {
    Running { next_player: Player },
    Ended,
}

/// Each cell in the board can either be empty or taken by one of the players.
#[derive(Clone, Copy)]
pub enum Cell {
    Empty,
    Taken { player: Player },
}

/// There are eight cardinal directions
const DIRECTIONS: usize = 8;

/// An array listing all the cardinal directions, represented by the coordinate delta to move in that direction
/// Example: if I am in cell (4, 5) and move NE, I go to cell (4, 5) + (1, -1) = (5, 4)
const DIRECTION: [(i8, i8); DIRECTIONS] = [
    ( 0, -1), //North
    ( 1, -1), //NE
    ( 1,  0), //East
    ( 1,  1), //SE
    ( 0,  1), //South
    (-1,  1), //SW
    (-1,  0), //West
    (-1, -1), //NW
    ];

/// The size of the board is a constant.
pub const BOARD_SIZE: usize = 8;

/// The board is given by a matrix of cells of size BOARD_SIZE and by which player has to move next.
#[derive(Clone, Copy)]
pub struct Game {
    board: [[Cell; BOARD_SIZE]; BOARD_SIZE],
    status: Status,
}

impl Game {
    /// Initializing a new game: starting positions on the board and Dark is the first to play
    pub fn new() -> Game {
        let mut board = [[Cell::Empty; BOARD_SIZE]; BOARD_SIZE];
        board[3][3] = Cell::Taken { player: Player::Light };
        board[4][4] = Cell::Taken { player: Player::Light };
        board[3][4] = Cell::Taken { player: Player::Dark };
        board[4][3] = Cell::Taken { player: Player::Dark };
        Game {
            board: board,
            status: Status::Running { next_player: Player::Dark },
        }
    }

    /// Return the game's board
    pub fn get_board(&self) -> [[Cell; BOARD_SIZE]; BOARD_SIZE] {
        self.board
    }

    /// Return the game's status
    pub fn get_status(&self) -> Status {
        self.status
    }

    /// Check that a given move is legal
    pub fn check_move (&self, (row, col): (usize, usize)) -> bool {

        // If the given coordinate falls out of the board or in a taken cell, the move cannot be legal
        if row >= BOARD_SIZE || col >= BOARD_SIZE {
            return false;
        } else if let Cell::Taken { player: _ } = self.board[row][col] {
            return false;
        }

        // If a move leads to eat in at least one direction, then it is legal
        for dir in 0..DIRECTIONS {
            if self.check_move_along_direction((row, col),  dir) {
                return true;
            }
        }

        false
    }

    // Check whether a move leads to eat in a specified direction
    fn check_move_along_direction (&self, (row, col): (usize, usize), dir: usize) -> bool {

        let (delta_ns, delta_ew) = DIRECTION[dir];

        // Need at least two cells' space in the given direction

        let mut col_i8: i8 = col as i8 + 2*delta_ew;
        if ( col_i8 < 0 ) || ( col_i8 >= BOARD_SIZE as i8 ) {
                return false;
        }

        let mut row_i8: i8 = row as i8 + 2*delta_ns;
        if ( row_i8 < 0 ) || ( row_i8 >= BOARD_SIZE as i8 ) {
                return false;
        }

        if let Status::Running { next_player } = self.status {

            // Next cell has to be owned by the other player
            if let Cell::Taken { player } = self.board[ ( row as i8 + delta_ns ) as usize ][ ( col as i8 + delta_ew ) as usize] {
                if player == next_player {
                    return false;
                }

                while let Cell::Taken { player } = self.board[ row_i8 as usize ][ col_i8 as usize] {
                    if player == next_player {
                        return true;
                    }

                    col_i8 += delta_ew;
                    if ( col_i8 < 0 ) || ( col_i8 >= BOARD_SIZE as i8 ) {
                            return false;
                    }

                    row_i8 += delta_ns;
                    if ( row_i8 < 0 ) || ( row_i8 >= BOARD_SIZE as i8 ) {
                            return false;
                    }

                }
            }
        }

        false
    }

    // Eats all of the opponent's occupied cells from a specified cell (given by its coordinates) in a specified direction
    // until it finds a cell of the current player
    // WARNING: this function do NOT perform any check about whether or not the move is legal
    fn eat_along_direction (&mut self, (row, col): (usize, usize), dir: usize) {

        if let Status::Running { next_player } = self.status {

            let (delta_ns, delta_ew) = DIRECTION[dir];

            self.board[ ( row as i8 + delta_ns ) as usize ][ ( col as i8 + delta_ew ) as usize] = Cell::Taken { player: next_player };

            let (mut row_i8, mut col_i8): (i8, i8) = (row as i8 + 2*delta_ns, col as i8 + 2*delta_ew);

            while let Cell::Taken { player: player_in_cell } = self.board[ row_i8 as usize ][ col_i8 as usize] {
                if next_player == player_in_cell {
                    break;
                }

                self.board[ row_i8 as usize ][ col_i8 as usize ] = Cell::Taken { player: next_player };

                row_i8 += delta_ns;
                col_i8 += delta_ew;
            }
        }
    }

    // Current player perform a move, after verifying that it is legal
    pub fn make_move (&mut self, (row, col): (usize, usize)) -> &Game {

        if row >= BOARD_SIZE || col >= BOARD_SIZE {
            return self;
        } else if let Cell::Taken { player: _ } = self.board[row][col] {
            return self;
        }

        let mut legal: bool = false;

        for dir in 0..DIRECTIONS {
            if self.check_move_along_direction((row, col),  dir) {
                self.eat_along_direction((row, col), dir);
                legal = true;
            }
        }

        // If a move is legal, the next player to play has to be determined
        // If the opposite player can make any move at all, it gets the turn
        // If not, if the previous player can make any move at all, it gets the turn
        // If not (that is, if no player can make any move at all) the game is ended
        if legal {
            if let Status::Running { next_player } = self.status {
                self.board[row][col] = Cell::Taken { player: next_player };

                self.status = Status::Running { next_player: next_player.opposite() };
                if self.can_move() {
                    return self;
                }

                self.status = Status::Running { next_player: next_player };
                if self.can_move() {
                    return self;
                }

                self.status = Status::Ended;
                return self;
            }
        }

        self
    }

    // Return whether or not next_player can make any move at all
    fn can_move(&self) -> bool {
        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                if self.check_move((row, col)) {
                    return true;
                }
            }
        }
        false
    }

    // Return the current score of the match
    pub fn get_score(&self) -> (u8, u8) {
        let (mut score_light, mut score_dark): (u8, u8) = (0, 0);

        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                match self.board[row][col] {
                    Cell::Taken { player: Player::Light } => score_light += 1,
                    Cell::Taken { player: Player::Dark } => score_dark += 1,
                    _ => {},
                }
            }
        }

        (score_light, score_dark)
    }

    pub fn get_turn(&self) -> u8 {
        let mut turn: u8 = 0;

        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                if let Cell::Taken { player: _ } =  self.board[row][col] {
                    turn += 1;
                }
            }
        }
        turn
    }

    pub fn get_cell(&self, (row, col): (usize, usize)) -> Cell {
        return self.board[row][col];
    }

}
<commit_msg>Performance, small fix<commit_after>// This module provides the main structures and mechanics of the game

/// There are two players playing the match: Light and Dark
#[derive(Clone, Copy, PartialEq)]
pub enum Player {
    Light,
    Dark,
}

impl Player {
    /// Get the player of the opposite kind to self
    fn opposite(&self) -> Player {
        match *self {
            Player::Light => {
                Player::Dark
                    }
            Player::Dark => {
                Player::Light
            }
        }
    }
}

/// A game can be in two status: either running (with a next player to play) or ended.
#[derive(Clone)]
pub enum Status {
    Running { next_player: Player },
    Ended,
}

/// Each cell in the board can either be empty or taken by one of the players.
#[derive(Clone, Copy)]
pub enum Cell {
    Empty,
    Taken { player: Player },
}

/// There are eight cardinal directions
const DIRECTIONS: usize = 8;

/// An array listing all the cardinal directions, represented by the coordinate delta to move in that direction
/// Example: if I am in cell (4, 5) and move NE, I go to cell (4, 5) + (1, -1) = (5, 4)
const DIRECTION: [(i8, i8); DIRECTIONS] = [
    ( 0, -1), //North
    ( 1, -1), //NE
    ( 1,  0), //East
    ( 1,  1), //SE
    ( 0,  1), //South
    (-1,  1), //SW
    (-1,  0), //West
    (-1, -1), //NW
    ];

/// The size of the board is a constant.
pub const BOARD_SIZE: usize = 8;

/// The board is given by a matrix of cells of size BOARD_SIZE and by which player has to move next.
#[derive(Clone)]
pub struct Game {
    board: [[Cell; BOARD_SIZE]; BOARD_SIZE],
    status: Status,
}

impl Game {
    /// Initializing a new game: starting positions on the board and Dark is the first to play
    pub fn new() -> Game {
        let mut board = [[Cell::Empty; BOARD_SIZE]; BOARD_SIZE];
        board[3][3] = Cell::Taken { player: Player::Light };
        board[4][4] = Cell::Taken { player: Player::Light };
        board[3][4] = Cell::Taken { player: Player::Dark };
        board[4][3] = Cell::Taken { player: Player::Dark };

        Game {
            board: board,
            status: Status::Running { next_player: Player::Dark },
        }
    }

    /// Return the game's board
    pub fn get_board(&self) -> [[Cell; BOARD_SIZE]; BOARD_SIZE] {
        self.board
    }

    /// Return the game's status
    pub fn get_status(&self) -> Status {
        self.status.clone()
    }

    /// Check that a given move is legal
    pub fn check_move (&self, (row, col): (usize, usize)) -> bool {

        // If the given coordinate falls out of the board or in a taken cell, the move cannot be legal
        if row >= BOARD_SIZE || col >= BOARD_SIZE {
            return false;
        } else if let Cell::Taken { player: _ } = self.board[row][col] {
            return false;
        }

        // If a move leads to eat in at least one direction, then it is legal
        for dir in 0..DIRECTIONS {
            if self.check_move_along_direction((row, col),  dir) {
                return true;
            }
        }

        false
    }

    // Check whether a move leads to eat in a specified direction
    fn check_move_along_direction (&self, (row, col): (usize, usize), dir: usize) -> bool {

        let (delta_ns, delta_ew) = DIRECTION[dir];

        // Need at least two cells' space in the given direction

        let mut col_i8: i8 = col as i8 + 2*delta_ew;
        if ( col_i8 < 0 ) || ( col_i8 >= BOARD_SIZE as i8 ) {
                return false;
        }

        let mut row_i8: i8 = row as i8 + 2*delta_ns;
        if ( row_i8 < 0 ) || ( row_i8 >= BOARD_SIZE as i8 ) {
                return false;
        }

        if let Status::Running { next_player } = self.status {

            // Next cell has to be owned by the other player
            if let Cell::Taken { player } = self.board[ ( row as i8 + delta_ns ) as usize ][ ( col as i8 + delta_ew ) as usize] {
                if player == next_player {
                    return false;
                }

                while let Cell::Taken { player } = self.board[ row_i8 as usize ][ col_i8 as usize] {
                    if player == next_player {
                        return true;
                    }

                    col_i8 += delta_ew;
                    if ( col_i8 < 0 ) || ( col_i8 >= BOARD_SIZE as i8 ) {
                            return false;
                    }

                    row_i8 += delta_ns;
                    if ( row_i8 < 0 ) || ( row_i8 >= BOARD_SIZE as i8 ) {
                            return false;
                    }

                }
            }
        }

        false
    }

    // Eats all of the opponent's occupied cells from a specified cell (given by its coordinates) in a specified direction
    // until it finds a cell of the current player
    // WARNING: this function do NOT perform any check about whether or not the move is legal
    fn eat_along_direction (&mut self, (row, col): (usize, usize), dir: usize) {

        if let Status::Running { next_player } = self.status {

            let (delta_ns, delta_ew) = DIRECTION[dir];

            self.board[ ( row as i8 + delta_ns ) as usize ][ ( col as i8 + delta_ew ) as usize] = Cell::Taken { player: next_player };

            let (mut row_i8, mut col_i8): (i8, i8) = (row as i8 + 2*delta_ns, col as i8 + 2*delta_ew);

            while let Cell::Taken { player: player_in_cell } = self.board[ row_i8 as usize ][ col_i8 as usize] {
                if next_player == player_in_cell {
                    break;
                }

                self.board[ row_i8 as usize ][ col_i8 as usize ] = Cell::Taken { player: next_player };

                row_i8 += delta_ns;
                col_i8 += delta_ew;
            }
        }
    }

    // Current player perform a move, after verifying that it is legal
    pub fn make_move (&mut self, (row, col): (usize, usize)) -> &Game {

        if row >= BOARD_SIZE || col >= BOARD_SIZE {
            return self;
        } else if let Cell::Taken { player: _ } = self.board[row][col] {
            return self;
        }

        let mut legal: bool = false;

        for dir in 0..DIRECTIONS {
            if self.check_move_along_direction((row, col),  dir) {
                self.eat_along_direction((row, col), dir);
                legal = true;
            }
        }

        // If a move is legal, the next player to play has to be determined
        // If the opposite player can make any move at all, it gets the turn
        // If not, if the previous player can make any move at all, it gets the turn
        // If not (that is, if no player can make any move at all) the game is ended
        if legal {
            if let Status::Running { next_player } = self.status {
                self.board[row][col] = Cell::Taken { player: next_player };

                self.status = Status::Running { next_player: next_player.opposite() };
                if self.can_move() {
                    return self;
                }

                self.status = Status::Running { next_player: next_player };
                if self.can_move() {
                    return self;
                }

                self.status = Status::Ended;
                return self;
            }
        }

        self
    }

    // Return whether or not next_player can make any move at all
    fn can_move(&self) -> bool {
        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                if self.check_move((row, col)) {
                    return true;
                }
            }
        }
        false
    }

    // Return the current score of the match
    pub fn get_score(&self) -> (u8, u8) {
        let (mut score_light, mut score_dark): (u8, u8) = (0, 0);

        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                match self.board[row][col] {
                    Cell::Taken { player: Player::Light } => score_light += 1,
                    Cell::Taken { player: Player::Dark } => score_dark += 1,
                    _ => {},
                }
            }
        }

        (score_light, score_dark)
    }

    pub fn get_turn(&self) -> u8 {
        let mut turn: u8 = 0;

        for row in 0..BOARD_SIZE {
            for col in 0..BOARD_SIZE {
                if let Cell::Taken { player: _ } =  self.board[row][col] {
                    turn += 1;
                }
            }
        }
        turn
    }

    pub fn get_cell(&self, (row, col): (usize, usize)) -> Cell {
        return self.board[row][col];
    }

}
<|endoftext|>


<commit_before>use futures::future::Future;
use futures::stream::Stream;
use glob::glob;
use hyper::{header, Chunk, Client, Method, Request, Response};
use hyper_rustls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};
use tokio_core::reactor;

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_content_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let content = serde_json::ser::to_string(&all_contents)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn build_request(&self, url: &str) -> Request {
        let token = String::from("token ") + &self.conf.token;
        let mut req: Request = Request::new(Method::Get, url.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        req
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn get_content_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let req = self.build_page_request(url, page);
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let to_io = |e| std::io::Error::new(std::io::ErrorKind::Other, e);
        let parse_body = |body: Chunk| Ok(serde_json::from_slice::<Vec<_>>(&body).map_err(to_io)?);
        let handle_response = |res: Response| res.body().concat2().and_then(parse_body);
        Ok(core.run(client.request(req).and_then(handle_response))?)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Tweak namings<commit_after>use futures::future::Future;
use futures::stream::Stream;
use glob::glob;
use hyper::{header, Chunk, Client, Method, Request, Response};
use hyper_rustls::HttpsConnector;
use serde_json;
use statics::TEMP_DIRNAME;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};
use tokio_core::reactor;

pub struct GithubClient {
    pub conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push(url);
        path
    }

    fn load_contents_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut contents = String::new();
        f.read_to_string(&mut contents)?;
        Ok((metadata, contents))
    }

    fn store_contents_to_cache(&self, url: &str, contents: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(contents.as_bytes())?;
        Ok(())
    }

    fn get_contents_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_contents_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let contents = serde_json::ser::to_string(&all_contents)?;
        self.store_contents_to_cache(url, &contents)?;
        Ok(contents)
    }

    fn build_request(&self, url: &str) -> Request {
        let token = String::from("token ") + &self.conf.token;
        let mut req: Request = Request::new(Method::Get, url.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        req
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request {
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        self.build_request(&url_p)
    }

    fn get_contents_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let req = self.build_page_request(url, page);
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let to_io = |e| std::io::Error::new(std::io::ErrorKind::Other, e);
        let parse_body = |body: Chunk| Ok(serde_json::from_slice::<Vec<_>>(&body).map_err(to_io)?);
        let handle_response = |res: Response| res.body().concat2().and_then(parse_body);
        Ok(core.run(client.request(req).and_then(handle_response))?)
    }

    fn get_contents(&self, url: &str) -> Result<String, CliError> {
        match self.load_contents_from_cache(url) {
            Ok((metadata, cache_contents)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_contents_from_url(url) {
                            Ok(contents_from_url) => Ok(contents_from_url),
                            Err(_) => Ok(cache_contents),
                        }
                    } else {
                        Ok(cache_contents)
                    }
                }
                Err(_) => Ok(cache_contents),
            },
            Err(_) => self.get_contents_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let contents = self.get_contents(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&contents)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&contents)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let contents = self.get_contents(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&contents)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let contents = self.get_contents(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&contents)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push(TEMP_DIRNAME);
        path.push("**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use card;
use std::fmt;

mod tests;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hand {
    pub cards: Vec<card::Card>,
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards,

        }
    }

    fn has_flush(&self) -> bool {
        let suit_mask: i64 = card::Suit::get_suit_mask(self.cards.first().unwrap().suit);
        for card in &self.cards[1..] {
            if (-suit_mask) & card.get_mask() != 0 {
                return false;
            }
        }
        true
    }

    fn has_straight(&self) -> bool {
        let mut ranks: i64 = 0;
        for card in &self.cards {
            ranks |= card.get_rank_mask();
        }

        let straight_matcher: i64 = 0b11111;
        let ace_low_matcher: i64 = 0b1000000001111;
        if ranks ^ ace_low_matcher == 0 {
            return true;
        }
        for i in 0..8 {
            if ranks ^ (straight_matcher << i) == 0 {
                return true;
            }
        }
        false
    }

    fn has_pair(&self) -> bool {
        let mut ranks: i64 = self.cards.first().unwrap().get_rank_mask();
        for card in &self.cards[1..] {
            if ranks | card.get_rank_mask() == ranks {
                return true
            }
            ranks |= card.get_rank_mask();
        }
        false
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum PokerRanking {
    HighCard,
    OnePair,
    TwoPair,
    Trips,
    Straight,
    Flush,
    FullHouse,
    Quads,
    StraightFlush,
}
<commit_msg>Reimplemented has_flush() to use get_suit_mask() instead of an absolute mask<commit_after>use card;
use std::fmt;

mod tests;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hand {
    pub cards: Vec<card::Card>,
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards,

        }
    }

    fn has_flush(&self) -> bool {
        let suits: i64 = self.cards.first().unwrap().get_suit_mask();
        for card in &self.cards[1..] {
            if suits | card.get_suit_mask() != suits {
                return false;
            }
        }
        true
    }

    fn has_straight(&self) -> bool {
        let mut ranks: i64 = 0;
        for card in &self.cards {
            ranks |= card.get_rank_mask();
        }

        let straight_matcher: i64 = 0b11111;
        let ace_low_matcher: i64 = 0b1000000001111;
        if ranks ^ ace_low_matcher == 0 {
            return true;
        }
        for i in 0..8 {
            if ranks ^ (straight_matcher << i) == 0 {
                return true;
            }
        }
        false
    }

    fn has_pair(&self) -> bool {
        let mut ranks: i64 = self.cards.first().unwrap().get_rank_mask();
        for card in &self.cards[1..] {
            if ranks | card.get_rank_mask() == ranks {
                return true
            }
            ranks |= card.get_rank_mask();
        }
        false
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum PokerRanking {
    HighCard,
    OnePair,
    TwoPair,
    Trips,
    Straight,
    Flush,
    FullHouse,
    Quads,
    StraightFlush,
}
<|endoftext|>