<commit_before>extern crate libc;

use array::Array;
use defines::AfError;
use dim4::Dim4;
use seq::Seq;
use defines::Aftype;
use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong};

type MutAfArray    = *mut self::libc::c_longlong;
type MutAfSeq      = *mut Seq;
type MutMutAfIndex = *mut *mut self::libc::c_longlong;
type MutAfIndex    = *mut self::libc::c_longlong;
type MutDouble     = *mut self::libc::c_double;
type MutUint       = *mut self::libc::c_uint;
type AfArray       = self::libc::c_longlong;
type AfIndex       = self::libc::c_longlong;
type DimT          = self::libc::c_longlong;
type SeqT          = self::libc::c_longlong;
type IndexT        = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_seq_index(result: MutMutAfIndex, input: *const Seq, is_batch: c_int) -> c_int;
    fn af_create_array_index(result: MutMutAfIndex, input: AfArray) -> c_int;
    fn af_release_index(indexer: MutAfIndex) -> c_int;
    fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const IndexT) -> c_int;
    fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int;
    fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const IndexT, rhs: AfArray) -> c_int;
    fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: *const IndexT) -> c_int;
    fn af_assign_gen(out: MutAfArray, lhs: AfArray, ndims: DimT, indices: *const IndexT, rhs: AfArray) -> c_int;
}

pub struct Index {
    handle: i64,
    is_batch: bool,
    is_seq: bool,
}

impl Index {
    #[allow(unused_mut)]
    pub fn new<T>(arr: Option<Array>, seq: Option<Seq>, is_batch: bool) -> Result<Index, AfError> {
        unsafe {
            let mut err_val: c_int = 0;
            let mut temp: i64 = 0;
            let mut is_seq = false;
            err_val = match arr {
                //c_func(&mut (x as *mut libc::c_void)); --> (&mut x) as *mut _ as *mut *mut libc::c_void.
                //&mut temp as MutMutAfIndex, x),
                Some(mut x) => { is_seq = false; af_create_array_index((&mut temp) as *mut _ as MutMutAfIndex, x.get() as AfArray) },
                None    => 0,
            };

            err_val = match seq {
                Some(mut x) => { is_seq = true; af_create_seq_index((&mut temp) as *mut _ as MutMutAfIndex, &mut x, is_batch as c_int) },
                None    => AfError::ERR_UNKNOWN as c_int,
            };

            match err_val {
                0 => Ok(Index {handle: temp, is_batch: is_batch, is_seq: is_seq}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn index(&self, input: Array, seqs: &[Seq]) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_index(&mut temp as MutAfArray
                                    , input.get() as AfArray, seqs.len() as u32
                                    , seqs.as_ptr() as *const SeqT);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn lookup(&self, input: Array, indices: Array, seq_dim: i32) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_lookup(&mut temp as MutAfArray
                                    , input.get() as AfArray
                                    , indices.get() as AfArray
                                    , seq_dim as c_uint);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn assign_seq(&self, lhs: Array, ndims: usize, seq_dim: i32, seqs: &[Seq], rhs: Array) -> Result<Array, AfError> {
        unsafe{
            let mut temp: i64 = 0;
            let err_val = af_assign_seq(&mut temp as MutAfArray
                                        , lhs.get() as AfArray
                                        , ndims as c_uint, seqs.as_ptr() as *const IndexT
                                        , rhs.get() as AfArray);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn index_gen(&self, input: Array, ndims: Dim4, indices: &[Index]) -> Result<Array, AfError> {
        unsafe{
            let mut temp: i64 = 0;
            let err_val = af_index_gen(&mut temp as MutAfArray
                                      , input.get() as AfArray
                                      , ndims.get().as_ptr() as DimT
                                      , indices.as_ptr() as *const IndexT);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn assign_gen(&self, lhs: Array, ndims: Dim4, indices: &[Index], rhs: Array) -> Result<Array, AfError> {
        unsafe{
            let mut temp: i64 = 0;
            let err_val = af_assign_gen(&mut temp as MutAfArray
                                        , lhs.get() as AfArray
                                        , ndims.get().as_ptr() as DimT
                                        , indices.as_ptr() as *const IndexT
                                        , rhs.get() as AfArray);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64 {
        self.handle
    }

    pub fn is_seq(&self) -> bool{
        self.is_seq
    }

    pub fn is_batch(&self) -> bool{
        self.is_seq
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_index(self.handle as MutAfIndex);
            match ret_val {
                0 => (),
                _ => panic!("Failed to destruct Index: {}", ret_val),
            }
        }
    }
}<commit_msg>forgot to push the actual index changes<commit_after>extern crate libc;

use array::Array;
use defines::AfError;
use dim4::Dim4;
use seq::Seq;
use defines::Aftype;
use self::libc::{c_int, c_uint, c_longlong};

type MutAfArray    = *mut self::libc::c_longlong;
type MutAfSeq      = *mut Seq;
type MutMutAfIndex = *mut *mut self::libc::c_longlong;
type MutAfIndex    = *mut self::libc::c_longlong;
type MutDouble     = *mut self::libc::c_double;
type MutUint       = *mut self::libc::c_uint;
type AfArray       = self::libc::c_longlong;
type AfIndex       = self::libc::c_longlong;
type DimT          = self::libc::c_longlong;
type SeqT          = self::libc::c_longlong;
type IndexT        = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_seq_index(result: MutMutAfIndex, input: *const Seq, is_batch: c_int) -> c_int;
    fn af_create_array_index(result: MutMutAfIndex, input: AfArray) -> c_int;
    fn af_release_index(indexer: MutAfIndex) -> c_int;
    fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const IndexT) -> c_int;
    fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int;
    fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const IndexT, rhs: AfArray) -> c_int;
    fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: *const IndexT) -> c_int;
    fn af_assign_gen(out: MutAfArray, lhs: AfArray, ndims: DimT, indices: *const IndexT, rhs: AfArray) -> c_int;
}

pub struct Index {
    handle: i64,
    is_batch: bool,
    is_seq: bool,
}

impl Index {
    #[allow(unused_mut)]
    pub fn new(arr: Option<Array>, seq: Option<Seq>, is_batch: bool) -> Result<Index, AfError> {
        unsafe {
            let mut err_val: c_int = 0;
            let mut temp: i64 = 0;
            let mut is_seq = false;
            err_val = match arr {
                //c_func(&mut (x as *mut libc::c_void)); --> (&mut x) as *mut _ as *mut *mut libc::c_void.
                //&mut temp as MutMutAfIndex, x),
                Some(mut x) => { is_seq = false; af_create_array_index((&mut temp) as *mut _ as MutMutAfIndex, x.get() as AfArray) },
                None    => 0,
            };

            err_val = match seq {
                Some(mut x) => { is_seq = true; af_create_seq_index((&mut temp) as *mut _ as MutMutAfIndex, &mut x, is_batch as c_int) },
                None    => AfError::ERR_UNKNOWN as c_int,
            };

            match err_val {
                0 => Ok(Index {handle: temp, is_batch: is_batch, is_seq: is_seq}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64 {
        self.handle
    }

    pub fn is_seq(&self) -> bool{
        self.is_seq
    }

    pub fn is_batch(&self) -> bool{
        self.is_batch
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_index(self.handle as MutAfIndex);
            match ret_val {
                0 => (),
                _ => panic!("Failed to destruct Index: {}", ret_val),
            }
        }
    }
}

pub fn index(input: &Array, seqs: &[Seq]) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_index(&mut temp as MutAfArray
                                , input.get() as AfArray, seqs.len() as u32
                                , seqs.as_ptr() as *const SeqT);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn row(input: &Array, row_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = [0, 0, 0, 0];
    match dims_err {
        Ok(dim) =>  dims = dim.get().clone(),
        Err(e)  =>  panic!("Error unwrapping dims in row(): {}", e),
    }

    let array_end = dims[0] as f64 * dims[1] as f64 * dims[2] as f64 * dims[3] as f64;
    let row_begin: f64 = dims[1] as f64 * row_num as f64;
    assert!(row_begin <= array_end - dims[1] as f64);

    let row_end: f64 = row_begin + dims[1] as f64 - 1.0;
    assert!(row_end <= array_end);

    let index = Index::new(None, Some(Seq::new(row_begin, row_end, 1.0)), false);
    println!("origin size {} x {} x {} x {}", dims[0], dims[1], dims[2], dims[3]);
    println!("passed index gen from {} to {}", row_begin, row_end);

    match index {
        Ok(i)  => { println!("index raw handle: {}", i.get()); index_gen(input, Dim4::new(&[1, 1, 1, 1]), &[i])},
        Err(e) => Err(AfError::from(e)),
    }
}

pub fn col(input: &Array, col_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = [0, 0, 0, 0];
    match dims_err {
        Ok(dim) =>  dims = dim.get().clone(),
        Err(e)  =>  panic!("Error unwrapping dims in col(): {}", e),
    }

    let input_type_err = input.get_type();
    let mut input_type = Aftype::F32;
    match input_type_err {
        Ok(t)   => input_type = t,
        Err(e)  => panic!("Error unwrapping type in col(): {}", e),
    }

    let mut indices = vec![col_num];
    for i in 0..dims[0]-1 {
        let last_element = indices[indices.len() - 1];
        indices.push(last_element + dims[0]);
    }

    let index_array = Array::new(Dim4::new(&dims), &indices, input_type);
    match index_array {
        Ok(a)  => {
                    let index = Index::new(Some(a), None, false);
                    match index {
                        Ok(i)  => index_gen(input, Dim4::new(&[1, 1, 1, 1]), &[i]),
                        Err(e) => Err(AfError::from(e)),
                    }
                  },
        Err(e) => Err(AfError::from(e)),
    }
}

pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_lookup(&mut temp as MutAfArray
                                , input.get() as AfArray
                                , indices.get() as AfArray
                                , seq_dim as c_uint);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_seq(lhs: &Array, ndims: usize, seqs: &[Seq], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_seq(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims as c_uint, seqs.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn index_gen(input: &Array, ndims: Dim4, indices: &[Index]) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_index_gen(&mut temp as MutAfArray
                                  , input.get() as AfArray
                                  , ndims.get().as_ptr() as DimT
                                  , indices.as_ptr() as *const IndexT);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_gen(lhs: &Array, ndims: Dim4, indices: &[Index], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_gen(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims.get().as_ptr() as DimT
                                    , indices.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}<|endoftext|>


<commit_before>pub type TokenList = Vec<(usize, Token)>;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
  BracketOpening,
  BracketClosing,
  Separator,
  Number(f64),
  Operator(char),
  Identifier(String),
  Skip,
  Unknown
}

pub struct Tokenizer {
  tokens: TokenList,

  value_position: usize,
  value: String,

  state: State,
  previous_state: State
}

#[derive(PartialEq, Copy, Clone, Debug)]
enum State {
  Front,
  General,
  Identifier,
  NumberSign,
  Number,
  NumberExponent,
  Operator
}

impl Default for Tokenizer {
  #[inline]
  fn default() -> Tokenizer {
    Tokenizer {
      tokens: TokenList::with_capacity(10),
      value_position: 0,
      value: String::with_capacity(10),
      state: State::Front,
      previous_state: State::General
    }
  }
}

pub trait StringProcessor {
  fn process(self: &mut Self, line: &str) -> &TokenList;
}

impl StringProcessor for Tokenizer {
  fn process(&mut self, line: &str) -> &TokenList {
    // println!("cap: {}", self.tokens.capacity());
    self.tokens.clear();
    self.value_position = 0;
    self.value.clear();
    self.state = State::Front;
    self.previous_state = State::General;

    for (position, character) in line.chars().enumerate() {
      if character.is_whitespace() {
        continue;
      }

      let mut token = Token::Skip;
      self.previous_state = self.state;

      self.implicit_multiplication(position, character);

      match character {
        '(' => {
          token = Token::BracketOpening;
          self.state = State::Front;
        },
        ')' => {
          token = Token::BracketClosing;
          self.state = State::General;
        },
        ',' => {
          token = Token::Separator;
          self.state = State::Front;
        },
        '-' | '+' if self.state == State::NumberExponent => {
          self.value.push(character);
          self.state = State::NumberExponent;
        },
        '-' | '+' if self.state == State::Front ||
                     self.state == State::Operator => {
          self.value.push(character);
          self.state = State::NumberSign;
        },
        '+' | '-' | '/' | '*' | '^' | '=' => {
          token = Token::Operator(character);
          self.state = State::Operator;
        },
        '_' if self.state == State::Front ||
               self.state == State::General ||
               self.state == State::Identifier => {
          self.value.push(character);
          self.state = State::Identifier;
        },
        'e' if self.state == State::Number => {
          self.value.push(character);
          self.state = State::NumberExponent;
        },
        '.' if self.state == State::Number ||
               self.state == State::General ||
               self.state == State::Front => {
          self.value.push(character);
          self.state = State::Number;
        },
        _ if character.is_numeric() => {
          self.value.push(character);
          if self.state == State::Front ||
             self.state == State::General ||
             self.state == State::Operator ||
             self.state == State::NumberSign {
            self.state = State::Number;
          }
        },
        _ if character.is_alphabetic() => {
          self.value.push(character);
          self.state = State::Identifier;
        },
        _ => {
          token = Token::Unknown;
          self.state = State::General;
        }
      }

      self.push_number_or_identifier(Some(position));

      if token != Token::Skip {
        self.tokens.push((position, token));
        self.value_position = position + 1;
      }
    }

    self.push_number_or_identifier(None);

    &self.tokens
  }
}

impl Tokenizer {
  #[inline(always)]
  fn push_number_or_identifier(&mut self, position: Option<usize>) {
    if position.is_some() {
      if self.state == State::Front || self.state == State::General || self.state == State::Operator {
        if self.previous_state == State::Number ||
           self.previous_state == State::NumberExponent {
          self.tokens.push((self.value_position,
                                 Token::Number(self.value.parse().unwrap())));
          self.value.clear();
        } else
        if self.previous_state == State::Identifier {
          self.tokens.push((self.value_position,
                                 Token::Identifier(self.value.to_lowercase())));
          self.value.clear();
        }
      }
    } else {
      if self.state == State::Number ||
         self.state == State::NumberExponent {
        self.tokens.push((self.value_position,
                               Token::Number(self.value.parse().unwrap())));
      } else
      if self.state == State::Identifier {
        self.tokens.push((self.value_position,
                               Token::Identifier(self.value.to_lowercase())));
      }
    }
  }

  #[inline(always)]
  fn implicit_multiplication(&mut self, position: usize, character: char) {
    if character == '(' || character.is_alphabetic() {
      if self.previous_state == State::NumberSign ||
         self.previous_state == State::NumberExponent ||
         (self.previous_state == State::Number && character != 'e') {

        self.tokens.push((self.value_position,
                               if self.previous_state == State::NumberSign {
                                 Token::Number(if self.value.starts_with('-') {-1.0} else {1.0})
                               } else {
                                 Token::Number(self.value.parse().unwrap())
                               }));

        self.value.clear();
        self.tokens.push((self.value_position, Token::Operator('*')));
        self.value_position = position;
        self.previous_state = State::General;
      }
    }
  }
}

macro_rules! tokenize {
  ($x:expr) => (Tokenizer::default().process($x).to_owned())
}

macro_rules! tokenize_ref {
  ($x:expr) => (Tokenizer::default().process($x))
}

#[cfg(test)]
mod tests {
  use tokenizer::*;

  #[test]
  fn test_brackets() {
    assert_eq!(tokenize!("(").first(), Some(&(0, Token::BracketOpening)));
    assert_eq!(tokenize!(")").first(), Some(&(0, Token::BracketClosing)));
  }

  #[test]
  fn test_operators() {
    assert_eq!(tokenize!("2+2").iter().skip(1).next(), Some(&(1, Token::Operator('+'))));
    assert_eq!(tokenize!("2-2").iter().skip(1).next(), Some(&(1, Token::Operator('-'))));
    assert_eq!(tokenize!("*").first(), Some(&(0, Token::Operator('*'))));
    assert_eq!(tokenize!("/").first(), Some(&(0, Token::Operator('/'))));
    assert_eq!(tokenize!("=").first(), Some(&(0, Token::Operator('='))));
    assert_eq!(tokenize!("^").first(), Some(&(0, Token::Operator('^'))));
  }

  #[test]
  fn test_identifiers() {
    assert_eq!(tokenize!("x").first(), Some(&(0, Token::Identifier("x".to_string()))));
    assert_eq!(tokenize!("x123x").first(), Some(&(0, Token::Identifier("x123x".to_string()))));
    assert_eq!(tokenize!("_foo_bar").first(), Some(&(0, Token::Identifier("_foo_bar".to_string()))));
    assert_eq!(tokenize!("_foo_123").first(), Some(&(0, Token::Identifier("_foo_123".to_string()))));
  }

  #[test]
  fn test_numbers() {
    assert_eq!(tokenize!("1").first(), Some(&(0, Token::Number(1.0))));
    assert_eq!(tokenize!("1.23").first(), Some(&(0, Token::Number(1.23))));
    assert_eq!(tokenize!(".23").first(), Some(&(0, Token::Number(0.23))));
  }

  #[test]
  fn test_numbers_scientific() {
    assert_eq!(tokenize!("1e23").first(), Some(&(0, Token::Number(1.0e23))));
    assert_eq!(tokenize!("1e-23").first(), Some(&(0, Token::Number(1.0e-23))));
    assert_eq!(tokenize!("1.01e+23").first(), Some(&(0, Token::Number(1.01e23))));
  }

  #[test]
  fn test_expressions() {
    let mut t = tokenize!("2+2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('+'))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));

    let mut t = tokenize!("2+x");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('+'))));
    assert_eq!(t.remove(0), ((2, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("x=2");
    assert_eq!(t.remove(0), ((0, Token::Identifier("x".to_string()))));
    assert_eq!(t.remove(0), ((1, Token::Operator('='))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));
  }

  #[test]
  fn test_numbers_signed() {
    assert_eq!(tokenize!("-2").first(), Some(&(0, Token::Number(-2.0))));
    assert_eq!(tokenize!(" -2").first(), Some(&(0, Token::Number(-2.0))));
    assert_eq!(tokenize!("+2").first(), Some(&(0, Token::Number(2.0))));

    assert_eq!(tokenize!("(-2)").iter().skip(1).next(), Some(&(1, Token::Number(-2.0))));
    assert_eq!(tokenize!("( -2)").iter().skip(1).next(), Some(&(1, Token::Number(-2.0))));
    assert_eq!(tokenize!("(+2)").iter().skip(1).next(), Some(&(1, Token::Number(2.0))));

    let mut t = tokenize!("2-+2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));

    let mut t = tokenize!("2--2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(-2.0))));
  }

  #[test]
  fn test_implicit_multiplication() {
    let mut t = tokenize!("2--x");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(-1.0))));
    assert_eq!(t.remove(0), ((2, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((3, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("-2x");
    assert_eq!(t.remove(0), ((0, Token::Number(-2.0))));
    assert_eq!(t.remove(0), ((0, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((2, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("-2(4)");
    assert_eq!(t.remove(0), ((0, Token::Number(-2.0))));
    assert_eq!(t.remove(0), ((0, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((2, Token::BracketOpening)));
    assert_eq!(t.remove(0), ((3, Token::Number(4.0))));
    assert_eq!(t.remove(0), ((4, Token::BracketClosing)));

  }
}

#[cfg(test)]
pub mod benchmarks {
  use super::*;
  use test::Bencher;

  pub fn add_sub_gen(n: usize) -> String {
    (0..n).map(|x| format!("{}-{}+", x, x).to_string()).fold(String::new(), |a, x| a+&x)+"0"
  }

  #[bench]
  #[ignore]
  fn bench_tokenizer(b: &mut Bencher) {
    let add_sub_r = &add_sub_gen(100000);
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      (0..10).fold(0, |a, x| a + x + tokenizer.process(add_sub_r).len())
    });
  }

  #[bench]
  #[ignore]
  fn bench_tokenizer_without_arena(b: &mut Bencher) {
    let add_sub_r = &add_sub_gen(100000);

    b.iter(|| {
      (0..10).fold(0, |a, x| {
        let mut tokenizer = Tokenizer::default();
        a + x + tokenizer.process(add_sub_r).len()
      })
    });
  }

  #[bench]
  fn bench_tokenizer_numbers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("3.1415926535897932").len()
    });
  }

  #[bench]
  fn bench_tokenizer_short_numbers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("2").len()
    });
  }

  #[bench]
  fn bench_tokenizer_identifiers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("_lorem_ipsum_dolor").len()
    });
  }

  #[bench]
  fn bench_tokenizer_short_identifiers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("x").len()
    });
  }

  #[bench]
  fn bench_tokenizer_brackets(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("(").len()
    });
  }

  #[bench]
  fn bench_tokenizer_operators(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("+").len()
    });
  }
}
<commit_msg>tuned tokenizer<commit_after>pub type TokenList = Vec<(usize, Token)>;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
  BracketOpening,
  BracketClosing,
  Separator,
  Number(f64),
  Operator(char),
  Identifier(String),
  Skip,
  Unknown
}

pub struct Tokenizer {
  tokens: TokenList,

  value_position: usize,
  value: String,

  state: State,
  previous_state: State
}

#[derive(PartialEq, Copy, Clone, Debug)]
enum State {
  Front,
  General,
  Identifier,
  NumberSign,
  Number,
  NumberExponent,
  Operator
}

impl Default for Tokenizer {
  #[inline]
  fn default() -> Tokenizer {
    Tokenizer {
      tokens: TokenList::with_capacity(10),
      value_position: 0,
      value: String::with_capacity(10),
      state: State::Front,
      previous_state: State::General
    }
  }
}

pub trait StringProcessor {
  fn process(self: &mut Self, line: &str) -> &TokenList;
}

impl StringProcessor for Tokenizer {
  fn process(&mut self, line: &str) -> &TokenList {
    // println!("cap: {}", self.tokens.capacity());
    self.tokens.clear();
    self.value_position = 0;
    self.value.clear();
    self.state = State::Front;
    self.previous_state = State::General;

    for (position, character) in line.chars().enumerate() {
      if character.is_whitespace() {
        continue;
      }

      let mut token = Token::Skip;
      self.previous_state = self.state;

      self.implicit_multiplication(position, character);

      match character {
        _ if character.is_numeric() => {
          self.value.push(character);
          if self.state == State::Front ||
             self.state == State::General ||
             self.state == State::Operator ||
             self.state == State::NumberSign {
            self.state = State::Number;
          }
        },
        '-' | '+' if self.state == State::Front ||
                     self.state == State::Operator => {
          self.value.push(character);
          self.state = State::NumberSign;
        },
        '-' | '+' if self.state == State::NumberExponent => {
          self.value.push(character);
          self.state = State::NumberExponent;
        },
        '+' | '-' | '/' | '*' | '^' | '=' => {
          token = Token::Operator(character);
          self.state = State::Operator;
        },
        'e' if self.state == State::Number => {
          self.value.push(character);
          self.state = State::NumberExponent;
        },
        _ if character.is_alphabetic() => {
          self.value.push(character);
          self.state = State::Identifier;
        },
        '_' if self.state == State::Identifier ||
               self.state == State::Front ||
               self.state == State::General => {
          self.value.push(character);
          self.state = State::Identifier;
        },
        '.' if self.state == State::Number ||
               self.state == State::Front ||
               self.state == State::General => {
          self.value.push(character);
          self.state = State::Number;
        },
        '(' => {
          token = Token::BracketOpening;
          self.state = State::Front;
        },
        ')' => {
          token = Token::BracketClosing;
          self.state = State::General;
        },
        ',' => {
          token = Token::Separator;
          self.state = State::Front;
        },
        _ => {
          token = Token::Unknown;
          self.state = State::General;
        }
      }

      self.push_number_or_identifier(Some(position));

      if token != Token::Skip {
        self.tokens.push((position, token));
        self.value_position = position + 1;
      }
    }

    self.push_number_or_identifier(None);

    &self.tokens
  }
}

impl Tokenizer {
  #[inline(always)]
  fn push_number_or_identifier(&mut self, position: Option<usize>) {
    if position.is_some() {
      if self.state == State::Front || self.state == State::General || self.state == State::Operator {
        if self.previous_state == State::Number ||
           self.previous_state == State::NumberExponent {
          self.tokens.push((self.value_position,
                                 Token::Number(self.value.parse().unwrap())));
          self.value.clear();
        } else
        if self.previous_state == State::Identifier {
          self.tokens.push((self.value_position,
                                 Token::Identifier(self.value.to_lowercase())));
          self.value.clear();
        }
      }
    } else {
      if self.state == State::Number ||
         self.state == State::NumberExponent {
        self.tokens.push((self.value_position,
                               Token::Number(self.value.parse().unwrap())));
      } else
      if self.state == State::Identifier {
        self.tokens.push((self.value_position,
                               Token::Identifier(self.value.to_lowercase())));
      }
    }
  }

  #[inline(always)]
  fn implicit_multiplication(&mut self, position: usize, character: char) {
    if character == '(' || character.is_alphabetic() {
      if self.previous_state == State::NumberSign ||
         self.previous_state == State::NumberExponent ||
         (self.previous_state == State::Number && character != 'e') {

        self.tokens.push((self.value_position,
                               if self.previous_state == State::NumberSign {
                                 Token::Number(if self.value.starts_with('-') {-1.0} else {1.0})
                               } else {
                                 Token::Number(self.value.parse().unwrap())
                               }));

        self.value.clear();
        self.tokens.push((self.value_position, Token::Operator('*')));
        self.value_position = position;
        self.previous_state = State::General;
      }
    }
  }
}

macro_rules! tokenize {
  ($x:expr) => (Tokenizer::default().process($x).to_owned())
}

macro_rules! tokenize_ref {
  ($x:expr) => (Tokenizer::default().process($x))
}

#[cfg(test)]
mod tests {
  use tokenizer::*;

  #[test]
  fn test_brackets() {
    assert_eq!(tokenize!("(").first(), Some(&(0, Token::BracketOpening)));
    assert_eq!(tokenize!(")").first(), Some(&(0, Token::BracketClosing)));
  }

  #[test]
  fn test_operators() {
    assert_eq!(tokenize!("2+2").iter().skip(1).next(), Some(&(1, Token::Operator('+'))));
    assert_eq!(tokenize!("2-2").iter().skip(1).next(), Some(&(1, Token::Operator('-'))));
    assert_eq!(tokenize!("*").first(), Some(&(0, Token::Operator('*'))));
    assert_eq!(tokenize!("/").first(), Some(&(0, Token::Operator('/'))));
    assert_eq!(tokenize!("=").first(), Some(&(0, Token::Operator('='))));
    assert_eq!(tokenize!("^").first(), Some(&(0, Token::Operator('^'))));
  }

  #[test]
  fn test_identifiers() {
    assert_eq!(tokenize!("x").first(), Some(&(0, Token::Identifier("x".to_string()))));
    assert_eq!(tokenize!("x123x").first(), Some(&(0, Token::Identifier("x123x".to_string()))));
    assert_eq!(tokenize!("_foo_bar").first(), Some(&(0, Token::Identifier("_foo_bar".to_string()))));
    assert_eq!(tokenize!("_foo_123").first(), Some(&(0, Token::Identifier("_foo_123".to_string()))));
  }

  #[test]
  fn test_numbers() {
    assert_eq!(tokenize!("1").first(), Some(&(0, Token::Number(1.0))));
    assert_eq!(tokenize!("1.23").first(), Some(&(0, Token::Number(1.23))));
    assert_eq!(tokenize!(".23").first(), Some(&(0, Token::Number(0.23))));
  }

  #[test]
  fn test_numbers_scientific() {
    assert_eq!(tokenize!("1e23").first(), Some(&(0, Token::Number(1.0e23))));
    assert_eq!(tokenize!("1e-23").first(), Some(&(0, Token::Number(1.0e-23))));
    assert_eq!(tokenize!("1.01e+23").first(), Some(&(0, Token::Number(1.01e23))));
  }

  #[test]
  fn test_expressions() {
    let mut t = tokenize!("2+2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('+'))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));

    let mut t = tokenize!("2+x");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('+'))));
    assert_eq!(t.remove(0), ((2, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("x=2");
    assert_eq!(t.remove(0), ((0, Token::Identifier("x".to_string()))));
    assert_eq!(t.remove(0), ((1, Token::Operator('='))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));
  }

  #[test]
  fn test_numbers_signed() {
    assert_eq!(tokenize!("-2").first(), Some(&(0, Token::Number(-2.0))));
    assert_eq!(tokenize!(" -2").first(), Some(&(0, Token::Number(-2.0))));
    assert_eq!(tokenize!("+2").first(), Some(&(0, Token::Number(2.0))));

    assert_eq!(tokenize!("(-2)").iter().skip(1).next(), Some(&(1, Token::Number(-2.0))));
    assert_eq!(tokenize!("( -2)").iter().skip(1).next(), Some(&(1, Token::Number(-2.0))));
    assert_eq!(tokenize!("(+2)").iter().skip(1).next(), Some(&(1, Token::Number(2.0))));

    let mut t = tokenize!("2-+2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(2.0))));

    let mut t = tokenize!("2--2");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(-2.0))));
  }

  #[test]
  fn test_implicit_multiplication() {
    let mut t = tokenize!("2--x");
    assert_eq!(t.remove(0), ((0, Token::Number(2.0))));
    assert_eq!(t.remove(0), ((1, Token::Operator('-'))));
    assert_eq!(t.remove(0), ((2, Token::Number(-1.0))));
    assert_eq!(t.remove(0), ((2, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((3, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("-2x");
    assert_eq!(t.remove(0), ((0, Token::Number(-2.0))));
    assert_eq!(t.remove(0), ((0, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((2, Token::Identifier("x".to_string()))));

    let mut t = tokenize!("-2(4)");
    assert_eq!(t.remove(0), ((0, Token::Number(-2.0))));
    assert_eq!(t.remove(0), ((0, Token::Operator('*'))));
    assert_eq!(t.remove(0), ((2, Token::BracketOpening)));
    assert_eq!(t.remove(0), ((3, Token::Number(4.0))));
    assert_eq!(t.remove(0), ((4, Token::BracketClosing)));

  }
}

#[cfg(test)]
pub mod benchmarks {
  use super::*;
  use test::Bencher;

  pub fn add_sub_gen(n: usize) -> String {
    (0..n).map(|x| format!("{}-{}+", x, x).to_string()).fold(String::new(), |a, x| a+&x)+"0"
  }

  #[bench]
  #[ignore]
  fn bench_tokenizer(b: &mut Bencher) {
    let add_sub_r = &add_sub_gen(100000);
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      (0..10).fold(0, |a, x| a + x + tokenizer.process(add_sub_r).len())
    });
  }

  #[bench]
  #[ignore]
  fn bench_tokenizer_without_arena(b: &mut Bencher) {
    let add_sub_r = &add_sub_gen(100000);

    b.iter(|| {
      (0..10).fold(0, |a, x| {
        let mut tokenizer = Tokenizer::default();
        a + x + tokenizer.process(add_sub_r).len()
      })
    });
  }

  #[bench]
  fn bench_tokenizer_numbers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("3.1415926535897932").len()
    });
  }

  #[bench]
  fn bench_tokenizer_short_numbers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("2").len()
    });
  }

  #[bench]
  fn bench_tokenizer_identifiers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("_lorem_ipsum_dolor").len()
    });
  }

  #[bench]
  fn bench_tokenizer_short_identifiers(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("x").len()
    });
  }

  #[bench]
  fn bench_tokenizer_brackets(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("(").len()
    });
  }

  #[bench]
  fn bench_tokenizer_operators(b: &mut Bencher) {
    let mut tokenizer = Tokenizer::default();

    b.iter(|| {
      tokenizer.process("+").len()
    });
  }
}
<|endoftext|>


<commit_before>/// The tokenizer for the query interpreter

use error::*;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Rc<Token>>
    },

    Index {
        idx: i64,
        next: Option<Rc<Token>>
    }
}

impl Token {

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { next: ref mut next, .. } => *next = Some(Rc::new(token)),
            &mut Token::Index { next: ref mut next, .. }      => *next = Some(Rc::new(token)),
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ident: ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

    #[cfg(test)]
    pub fn idx(&self) -> i64 {
        match self {
            &Token::Index { idx: i, .. } => i,
            _ => unreachable!(),
        }
    }
}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[-?\d+\]$").unwrap();
        }

        if has_array_brackets(s) {
            match RE.captures(s) {
                None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
                Some(captures) => {
                    match captures.get(0) {
                        None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                        Some(mtch) => {
                            let mtch = without_array_brackets(mtch.as_str());
                            let i : i64 = FromStr::from_str(&mtch).unwrap(); // save because regex
                            Ok(Token::Index {
                                idx: i,
                                next: None,
                            })
                        }
                    }
                }
            }
        } else {
            Ok(Token::Identifier { ident: String::from(s), next: None })
        }

    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::*;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier {
                ident: ident,
                next: None
            } => {
                assert_eq!(String::from("example"), ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!(1, Rc::strong_count(&next));
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!(1, Rc::strong_count(&next));
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        use std::ops::Deref;

        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Rc::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Rc::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Rc::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    quickcheck! {
        fn test_array_index(i: i64) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index {
                    idx: i,
                    next: None,
                }) => true,
                _ => false,
            }
        }
    }

}
<commit_msg>Refactor: Simplify mk_token_object()<commit_after>/// The tokenizer for the query interpreter

use error::*;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Identifier {
        ident: String,
        next: Option<Rc<Token>>
    },

    Index {
        idx: i64,
        next: Option<Rc<Token>>
    }
}

impl Token {

    pub fn set_next(&mut self, token: Token) {
        match self {
            &mut Token::Identifier { next: ref mut next, .. } => *next = Some(Rc::new(token)),
            &mut Token::Index { next: ref mut next, .. }      => *next = Some(Rc::new(token)),
        }
    }

    #[cfg(test)]
    pub fn identifier(&self) -> &String {
        match self {
            &Token::Identifier { ident: ref ident, .. } => &ident,
            _ => unreachable!(),
        }
    }

    #[cfg(test)]
    pub fn idx(&self) -> i64 {
        match self {
            &Token::Index { idx: i, .. } => i,
            _ => unreachable!(),
        }
    }
}

pub fn tokenize_with_seperator(query: &String, seperator: char) -> Result<Token> {
    use std::str::Split;

    /// Creates a Token object from a string
    ///
    /// # Panics
    ///
    /// * If the internal regex does not compile (should never happen)
    /// * If the token is non-valid (that is, a array index with a non-i64)
    /// * If the regex does not find anything
    /// * If the integer in the brackets (`[]`) cannot be parsed to a valid i64
    ///
    /// # Incorrect behaviour
    ///
    /// * If the regex finds multiple captures
    ///
    /// # Returns
    ///
    /// The `Token` object with the correct identifier/index for this token and no next token.
    ///
    fn mk_token_object(s: &str) -> Result<Token> {
        use regex::Regex;
        use std::str::FromStr;

        lazy_static! {
            static ref RE: Regex = Regex::new(r"^\[-?\d+\]$").unwrap();
        }

        if !has_array_brackets(s) {
            return Ok(Token::Identifier { ident: String::from(s), next: None });
        }

        match RE.captures(s) {
            None => return Err(Error::from(ErrorKind::ArrayAccessWithoutIndex)),
            Some(captures) => {
                match captures.get(0) {
                    None => Ok(Token::Identifier { ident: String::from(s), next: None }),
                    Some(mtch) => {
                        let mtch = without_array_brackets(mtch.as_str());
                        let i : i64 = FromStr::from_str(&mtch).unwrap(); // save because regex
                        Ok(Token::Index {
                            idx: i,
                            next: None,
                        })
                    }
                }
            }
        }
    }

    /// Check whether a str begins with '[' and ends with ']'
    fn has_array_brackets(s: &str) -> bool {
        s.as_bytes()[0] == b'[' && s.as_bytes()[s.len() - 1] == b']'
    }

    /// Remove '[' and ']' from a str
    fn without_array_brackets(s: &str) -> String {
        s.replace("[","").replace("]","")
    }

    fn build_token_tree(split: &mut Split<char>, last: &mut Token) -> Result<()> {
        match split.next() {
            None        => { /* No more tokens */ }
            Some(token) => {
                let mut token = try!(mk_token_object(token));
                try!(build_token_tree(split, &mut token));
                last.set_next(token);
            }
        }
        Ok(())
    }

    if query.is_empty() {
        return Err(Error::from(ErrorKind::EmptyQueryError));
    }

    let mut tokens = query.split(seperator);

    match tokens.next() {
        None        => Err(Error::from(ErrorKind::EmptyQueryError)),
        Some(token) => {
            if token.len() == 0 {
                return Err(Error::from(ErrorKind::EmptyIdentifier));
            }
            let mut tok = try!(mk_token_object(token));
            let _       = try!(build_token_tree(&mut tokens, &mut tok));
            Ok(tok)
        }
    }
}

#[cfg(test)]
mod test {
    use error::*;
    use super::*;

    use std::ops::Deref;

    #[test]
    fn test_tokenize_empty_query_to_error() {
        let tokens = tokenize_with_seperator(&String::from(""), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyQueryError { .. }));
    }

    #[test]
    fn test_tokenize_seperator_only() {
        let tokens = tokenize_with_seperator(&String::from("."), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::EmptyIdentifier { .. }));
    }

    #[test]
    fn test_tokenize_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_with_array_brackets_only() {
        let tokens = tokenize_with_seperator(&String::from("a.b.c.[]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_identifiers_in_array_brackets() {
        let tokens = tokenize_with_seperator(&String::from("[a]"), '.');
        assert!(tokens.is_err());
        let tokens = tokens.unwrap_err();

        let errkind = tokens.kind();
        assert!(is_match!(errkind, &ErrorKind::ArrayAccessWithoutIndex { .. }));
    }

    #[test]
    fn test_tokenize_single_token_query() {
        let tokens = tokenize_with_seperator(&String::from("example"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier {
                ident: ident,
                next: None
            } => {
                assert_eq!(String::from("example"), ident);
                true
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_double_token_query() {
        let tokens = tokenize_with_seperator(&String::from("a.b"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!(1, Rc::strong_count(&next));
                assert_eq!("b", next.deref().identifier());
                match next.deref() {
                    &Token::Identifier { next: None, .. } => true,
                    _ => false
                }
            },
            _ => false,
        });
        assert_eq!("a", tokens.identifier());
    }

    #[test]
    fn test_tokenize_ident_then_array_query() {
        let tokens = tokenize_with_seperator(&String::from("a.[0]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());
        assert!(match tokens {
            Token::Identifier { next: Some(ref next), .. } => {
                assert_eq!(1, Rc::strong_count(&next));
                match next.deref() {
                    &Token::Index { idx: 0, next: None } => true,
                    _ => false
                }
            },
            _ => false,
        });
    }

    #[test]
    fn test_tokenize_many_idents_then_array_query() {
        use std::ops::Deref;

        let tokens = tokenize_with_seperator(&String::from("a.b.c.[1000]"), '.');
        assert!(tokens.is_ok());
        let tokens = tokens.unwrap();

        assert_eq!("a", tokens.identifier());

        let expected =
            Token::Identifier {
                ident: String::from("a"),
                next: Some(Rc::new(Token::Identifier {
                    ident: String::from("b"),
                    next: Some(Rc::new(Token::Identifier {
                        ident: String::from("c"),
                        next: Some(Rc::new(Token::Index {
                            idx: 1000,
                            next: None,
                        })),
                    })),
                })),
            };

        assert_eq!(expected, tokens);
    }

    quickcheck! {
        fn test_array_index(i: i64) -> bool {
            match tokenize_with_seperator(&format!("[{}]", i), '.') {
                Ok(Token::Index {
                    idx: i,
                    next: None,
                }) => true,
                _ => false,
            }
        }
    }

}
<|endoftext|>


<commit_before>use super::action::Action;
use super::game_state::GameState;

pub trait Agent {
    fn act(&self, game_state: &GameState) -> Action;
}

pub struct FoldingAgent {}

impl Agent for FoldingAgent {
    fn act(&self, game_state: &GameState) -> Action {
        match (
            game_state.current_round_data(),
            game_state.num_active_players(),
        ) {
            (Some(round), 1) => Action::Bet(round.bet),
            _ => Action::Fold,
        }
    }
}

pub struct CallingAgent {}

impl Agent for CallingAgent {
    fn act(&self, game_state: &GameState) -> Action {
        if let Some(round) = game_state.current_round_data() {
            Action::Bet(round.bet)
        } else {
            Action::Fold
        }
    }
}
<commit_msg>Clean up CallingAgen<commit_after>use super::action::Action;
use super::game_state::GameState;

pub trait Agent {
    fn act(&self, game_state: &GameState) -> Action;
}

pub struct FoldingAgent {}

impl Agent for FoldingAgent {
    fn act(&self, game_state: &GameState) -> Action {
        match (
            game_state.current_round_data(),
            game_state.num_active_players(),
        ) {
            (Some(round), 1) => Action::Bet(round.bet),
            _ => Action::Fold,
        }
    }
}

pub struct CallingAgent {}

impl Agent for CallingAgent {
    fn act(&self, game_state: &GameState) -> Action {
        game_state
            .current_round_data()
            .map_or_else(|| Action::Fold, |round| Action::Bet(round.bet))
    }
}
<|endoftext|>


<commit_before>//! Awesome compatibility modules

use wlroots;

use rlua::{self, LightUserData, Lua, Table};
use std::{env, mem, path::PathBuf};
use xcb::{xkb, Connection};
use awesome::lua::setup_lua;

mod awesome;
mod button;
mod class;
mod client;
mod drawable;
mod drawin;
mod key;
pub mod keygrabber;
pub mod lua;
mod mouse;
pub mod mousegrabber;
mod object;
mod property;
mod root;
mod screen;
pub mod signal;
mod tag;
mod xproperty;

pub use self::lua::{NEXT_LUA, LUA};

pub use self::drawin::{Drawin, DRAWINS_HANDLE};
pub use self::key::Key;
pub use self::keygrabber::keygrabber_handle;
pub use self::mousegrabber::mousegrabber_handle;
pub use self::object::{Object, Objectable};
pub use self::root::ROOT_KEYS_HANDLE;
pub use self::signal::*;

use compositor::Server;

pub const GLOBAL_SIGNALS: &'static str = "__awesome_global_signals";
pub const XCB_CONNECTION_HANDLE: &'static str = "__xcb_connection";

/// Called from `wayland_glib_interface.c` after every call back into the wayland event loop.
///
/// This restarts the Lua thread if there is a new one pending
#[no_mangle]
pub extern "C" fn refresh_awesome() {
    NEXT_LUA.with(|new_lua_check| {
        if new_lua_check.get() {
            new_lua_check.set(false);
            LUA.with(|lua| {
                let mut lua = lua.borrow_mut();
                unsafe {
                    *lua = rlua::Lua::new_with_debug();
                }
            });
            let compositor = wlroots::compositor_handle().unwrap();
            setup_lua(compositor);
        }
    });
}

pub fn init(lua: &Lua, server: &mut Server) -> rlua::Result<()> {
    setup_awesome_path(lua)?;
    setup_global_signals(lua)?;
    setup_xcb_connection(lua)?;
    button::init(lua)?;
    awesome::init(lua)?;
    key::init(lua)?;
    client::init(lua)?;
    screen::init(lua, server)?;
    keygrabber::init(lua)?;
    root::init(lua)?;
    mouse::init(lua)?;
    tag::init(lua)?;
    drawin::init(lua)?;
    drawable::init(lua)?;
    mousegrabber::init(lua)?;
    Ok(())
}

fn setup_awesome_path(lua: &Lua) -> rlua::Result<()> {
    let globals = lua.globals();
    let package: Table = globals.get("package")?;
    let mut path = package.get::<_, String>("path")?;
    let mut cpath = package.get::<_, String>("cpath")?;

    for mut xdg_data_path in env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".into())
                                                      .split(':')
                                                      .map(PathBuf::from)
    {
        xdg_data_path.push("awesome/lib");
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua",
                               xdg_data_path.as_os_str().to_string_lossy()));
        cpath.push_str(&format!(";{}/?.so", xdg_data_path.into_os_string().to_string_lossy()));
    }

    for mut xdg_config_path in env::var("XDG_CONFIG_DIRS").unwrap_or("/etc/xdg".into())
                                                          .split(':')
                                                          .map(PathBuf::from)
    {
        xdg_config_path.push("awesome");
        cpath.push_str(&format!(";{}/?.so",
                                xdg_config_path.into_os_string().to_string_lossy()));
    }

    package.set("path", path)?;
    package.set("cpath", cpath)?;

    Ok(())
}

/// Set up global signals value
///
/// We need to store this in Lua, because this make it safer to use.
fn setup_global_signals(lua: &Lua) -> rlua::Result<()> {
    lua.set_named_registry_value(GLOBAL_SIGNALS, lua.create_table()?)
}

/// Sets up the xcb connection and stores it in Lua (for us to access it later)
fn setup_xcb_connection(lua: &Lua) -> rlua::Result<()> {
    let con = match Connection::connect(None) {
        Err(err) => {
            error!("Way Cooler requires XWayland in order to function");
            error!("However, xcb could not connect to it. Is it running?");
            error!("{:?}", err);
            panic!("Could not connect to XWayland instance");
        }
        Ok(con) => con.0
    };
    // Tell xcb we are using the xkb extension
    match xkb::use_extension(&con, 1, 0).get_reply() {
        Ok(r) => {
            if !r.supported() {
                panic!("xkb-1.0 is not supported");
            }
        }
        Err(err) => {
            panic!("Could not get xkb extension supported version {:?}", err);
        }
    }
    lua.set_named_registry_value(XCB_CONNECTION_HANDLE,
                                  LightUserData(con.get_raw_conn() as _))?;
    mem::forget(con);
    Ok(())
}

pub fn dummy<'lua>(_: &'lua Lua, _: rlua::Value) -> rlua::Result<()> {
    Ok(())
}
<commit_msg>cargo fmt src/awesome/mod.rs<commit_after>//! Awesome compatibility modules

use wlroots;

use awesome::lua::setup_lua;
use rlua::{self, LightUserData, Lua, Table};
use std::{env, mem, path::PathBuf};
use xcb::{xkb, Connection};

mod awesome;
mod button;
mod class;
mod client;
mod drawable;
mod drawin;
mod key;
pub mod keygrabber;
pub mod lua;
mod mouse;
pub mod mousegrabber;
mod object;
mod property;
mod root;
mod screen;
pub mod signal;
mod tag;
mod xproperty;

pub use self::lua::{LUA, NEXT_LUA};

pub use self::drawin::{Drawin, DRAWINS_HANDLE};
pub use self::key::Key;
pub use self::keygrabber::keygrabber_handle;
pub use self::mousegrabber::mousegrabber_handle;
pub use self::object::{Object, Objectable};
pub use self::root::ROOT_KEYS_HANDLE;
pub use self::signal::*;

use compositor::Server;

pub const GLOBAL_SIGNALS: &'static str = "__awesome_global_signals";
pub const XCB_CONNECTION_HANDLE: &'static str = "__xcb_connection";

/// Called from `wayland_glib_interface.c` after every call back into the
/// wayland event loop.
///
/// This restarts the Lua thread if there is a new one pending
#[no_mangle]
pub extern "C" fn refresh_awesome() {
    NEXT_LUA.with(|new_lua_check| {
                      if new_lua_check.get() {
                          new_lua_check.set(false);
                          LUA.with(|lua| {
                                       let mut lua = lua.borrow_mut();
                                       unsafe {
                                           *lua = rlua::Lua::new_with_debug();
                                       }
                                   });
                          let compositor = wlroots::compositor_handle().unwrap();
                          setup_lua(compositor);
                      }
                  });
}

pub fn init(lua: &Lua, server: &mut Server) -> rlua::Result<()> {
    setup_awesome_path(lua)?;
    setup_global_signals(lua)?;
    setup_xcb_connection(lua)?;
    button::init(lua)?;
    awesome::init(lua)?;
    key::init(lua)?;
    client::init(lua)?;
    screen::init(lua, server)?;
    keygrabber::init(lua)?;
    root::init(lua)?;
    mouse::init(lua)?;
    tag::init(lua)?;
    drawin::init(lua)?;
    drawable::init(lua)?;
    mousegrabber::init(lua)?;
    Ok(())
}

fn setup_awesome_path(lua: &Lua) -> rlua::Result<()> {
    let globals = lua.globals();
    let package: Table = globals.get("package")?;
    let mut path = package.get::<_, String>("path")?;
    let mut cpath = package.get::<_, String>("cpath")?;

    for mut xdg_data_path in
        env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".into())
                                 .split(':')
                                 .map(PathBuf::from)
    {
        xdg_data_path.push("awesome/lib");
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua",
                               xdg_data_path.as_os_str().to_string_lossy()));
        cpath.push_str(&format!(";{}/?.so", xdg_data_path.into_os_string().to_string_lossy()));
    }

    for mut xdg_config_path in env::var("XDG_CONFIG_DIRS").unwrap_or("/etc/xdg".into())
                                                          .split(':')
                                                          .map(PathBuf::from)
    {
        xdg_config_path.push("awesome");
        cpath.push_str(&format!(";{}/?.so",
                                xdg_config_path.into_os_string().to_string_lossy()));
    }

    package.set("path", path)?;
    package.set("cpath", cpath)?;

    Ok(())
}

/// Set up global signals value
///
/// We need to store this in Lua, because this make it safer to use.
fn setup_global_signals(lua: &Lua) -> rlua::Result<()> {
    lua.set_named_registry_value(GLOBAL_SIGNALS, lua.create_table()?)
}

/// Sets up the xcb connection and stores it in Lua (for us to access it later)
fn setup_xcb_connection(lua: &Lua) -> rlua::Result<()> {
    let con = match Connection::connect(None) {
        Err(err) => {
            error!("Way Cooler requires XWayland in order to function");
            error!("However, xcb could not connect to it. Is it running?");
            error!("{:?}", err);
            panic!("Could not connect to XWayland instance");
        }
        Ok(con) => con.0
    };
    // Tell xcb we are using the xkb extension
    match xkb::use_extension(&con, 1, 0).get_reply() {
        Ok(r) => {
            if !r.supported() {
                panic!("xkb-1.0 is not supported");
            }
        }
        Err(err) => {
            panic!("Could not get xkb extension supported version {:?}", err);
        }
    }
    lua.set_named_registry_value(XCB_CONNECTION_HANDLE,
                                  LightUserData(con.get_raw_conn() as _))?;
    mem::forget(con);
    Ok(())
}

pub fn dummy<'lua>(_: &'lua Lua, _: rlua::Value) -> rlua::Result<()> {
    Ok(())
}
<|endoftext|>


<commit_before>use std::ops::Mul;
use na::{self, Matrix4, Matrix2, Similarity3, U3, Affine3};

use {Vector2f, Vector3f, Point3f, gamma};

#[derive(Debug,Clone)]
pub struct Transform {
    pub m: Matrix4<f32>,
    pub m_inv: Matrix4<f32>,
}

impl Transform {
    pub fn new(t: Vector3f, r: Vector3f, s: f32) -> Transform {
        Transform::from_similarity(&Similarity3::new(t, r, s))
    }

    pub fn from_similarity(s: &Similarity3<f32>) -> Transform {
        Transform {
            m: s.to_homogeneous(),
            m_inv: s.inverse().to_homogeneous(),
        }
    }

    pub fn rotate(angle: f32, v: Vector3f) -> Transform {
        Transform::new(na::zero(), v * angle, 1.0)
    }

    pub fn rot_x(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::x() * angle.to_radians(), 1.0)
    }

    pub fn rot_y(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::y() * angle.to_radians(), 1.0)
    }

    pub fn rot_z(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::z() * angle.to_radians(), 1.0)
    }

    pub fn rot(ax: f32, ay: f32, az: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::new(ax, ay, az), 1.0)
    }

    pub fn translate(t: Vector3f) -> Transform {
        Transform::new(t, na::zero(), 1.0)
    }

    pub fn translate_x(t: f32) -> Transform {
        Transform::new(Vector3f::x() * t, na::zero(), 1.0)
    }

    pub fn translate_y(t: f32) -> Transform {
        Transform::new(Vector3f::y() * t, na::zero(), 1.0)
    }

    pub fn translate_z(t: f32) -> Transform {
        Transform::new(Vector3f::z() * t, na::zero(), 1.0)
    }

    pub fn scale_uniform(s: f32) -> Transform {
        Transform::new(na::zero(), na::zero(), s)
    }

    pub fn scale(sx: f32, sy: f32, sz: f32) -> Transform {
        let mat = Matrix4::new_nonuniform_scaling(&Vector3f::new(sx, sy, sz));
        Transform {
            m: mat,
            m_inv: mat.try_inverse().unwrap(),
        }
    }

    pub fn inverse(&self) -> Self {
        Transform {
            m: self.m_inv,
            m_inv: self.m,
        }
    }

    /// Transform the given point using the given transformation and also return a vector of the
    /// absolute error introduced for each coordinate.
    pub fn transform_point(&self, p: &Point3f) -> (Point3f, Vector3f) {
        let (x, y, z) = (p.x, p.y, p.z);
        let tp = self * p;
        let m = self.m;
        let x_abs_sum = (m[(0, 0)] * x).abs() + (m[(0, 1)] * y).abs() + (m[(0, 2)] * z).abs() +
                        m[(0, 3)].abs();
        let y_abs_sum = (m[(1, 0)] * x).abs() + (m[(1, 1)] * y).abs() + (m[(1, 2)] * z).abs() +
                        m[(1, 3)].abs();
        let z_abs_sum = (m[(2, 0)] * x).abs() + (m[(2, 1)] * y).abs() + (m[(2, 2)] * z).abs() +
                        m[(2, 3)].abs();
        let p_err = gamma(3) * Vector3f::new(x_abs_sum, y_abs_sum, z_abs_sum);

        (tp, p_err)
    }

    pub fn transform_point_with_error(&self,
                                      p: &Point3f,
                                      p_error: &Vector3f)
                                      -> (Point3f, Vector3f) {
        let (x, y, z) = (p.x, p.y, p.z);
        let tp = self * p;
        let m = self.m;
        let x_abs_err = (gamma(3) + 1.0) *
                        ((m[(0, 0)] * p_error.x).abs() + (m[(0, 1)] * p_error.y).abs() +
                         (m[(0, 2)] * p_error.z).abs()) +
                        gamma(3) *
                        ((m[(0, 0)] * x).abs() + (m[(0, 1)] * y).abs() + (m[(0, 2)] * z).abs() +
                         m[(0, 3)].abs());
        let y_abs_err = (gamma(3) + 1.0) *
                        ((m[(1, 0)] * p_error.x).abs() + (m[(1, 1)] * p_error.y).abs() +
                         (m[(1, 2)] * p_error.z).abs()) +
                        gamma(3) *
                        ((m[(1, 0)] * x).abs() + (m[(1, 1)] * y).abs() + (m[(1, 2)] * z).abs() +
                         m[(1, 3)].abs());
        let z_abs_err = (gamma(3) + 1.0) *
                        ((m[(2, 0)] * p_error.x).abs() + (m[(2, 1)] * p_error.y).abs() +
                         (m[(2, 2)] * p_error.z).abs()) +
                        gamma(3) *
                        ((m[(2, 0)] * x).abs() + (m[(2, 1)] * y).abs() + (m[(2, 2)] * z).abs() +
                         m[(2, 3)].abs());
        let p_err = Vector3f::new(x_abs_err, y_abs_err, z_abs_err);

        (tp, p_err)
    }

    /// Transform the given point using the given transformation and also return a vector of the
    /// absolute error introduced for each coordinate.
    pub fn transform_vector(&self, v: &Vector3f) -> (Vector3f, Vector3f) {
        let (x, y, z) = (v.x, v.y, v.z);
        let tv = self * v;
        let m = self.m;
        let x_abs_sum = na::abs(&(m[(0, 0)] * x)) + na::abs(&(m[(0, 1)] * y)) +
                        na::abs(&(m[(0, 2)] * z)) + na::abs(&m[(0, 3)]);
        let y_abs_sum = na::abs(&(m[(1, 0)] * x)) + na::abs(&(m[(1, 1)] * y)) +
                        na::abs(&(m[(1, 2)] * z)) + na::abs(&m[(1, 3)]);
        let z_abs_sum = na::abs(&(m[(2, 0)] * x)) + na::abs(&(m[(2, 1)] * y)) +
                        na::abs(&(m[(2, 2)] * z)) + na::abs(&m[(2, 3)]);
        let v_err = gamma(3) * Vector3f::new(x_abs_sum, y_abs_sum, z_abs_sum);

        (tv, v_err)
    }

    pub fn transform_normal(&self, normal: &Vector3f) -> Vector3f {
        let m = self.m_inv.transpose();
        m.fixed_slice::<U3, U3>(0, 0) * *normal
    }
}

impl Default for Transform {
    fn default() -> Self {
        Transform {
            m: na::one(),
            m_inv: na::one(),
        }
    }
}

impl<'a, 'b> Mul<&'a Point3f> for &'b Transform {
    type Output = Point3f;

    fn mul(self, p: &'a Point3f) -> Point3f {
        let x = p.x;
        let y = p.y;
        let z = p.z;
        let xp = self.m[(0, 0)] * x + self.m[(0, 1)] * y + self.m[(0, 2)] * z + self.m[(0, 3)];
        let yp = self.m[(1, 0)] * x + self.m[(1, 1)] * y + self.m[(1, 2)] * z + self.m[(1, 3)];
        let zp = self.m[(2, 0)] * x + self.m[(2, 1)] * y + self.m[(2, 2)] * z + self.m[(2, 3)];
        let wp = self.m[(3, 0)] * x + self.m[(3, 1)] * y + self.m[(3, 2)] * z + self.m[(3, 3)];

        assert!(wp != 0.0);

        if wp == 1.0 {
            Point3f::new(xp, yp, zp)
        } else {
            Point3f::new(xp, yp, zp) / wp
        }
    }
}

impl<'a, 'b> Mul<&'a Vector3f> for &'b Transform {
    type Output = Vector3f;

    fn mul(self, v: &'a Vector3f) -> Vector3f {
        let x = v.x;
        let y = v.y;
        let z = v.z;

        Vector3f::new(self.m[(0, 0)] * x + self.m[(0, 1)] * y + self.m[(0, 2)] * z,
                      self.m[(1, 0)] * x + self.m[(1, 1)] * y + self.m[(1, 2)] * z,
                      self.m[(2, 0)] * x + self.m[(2, 1)] * y + self.m[(2, 2)] * z)

    }
}

impl<'a, 'b> Mul<&'a Transform> for &'b Transform {
    type Output = Transform;

    fn mul(self, t: &'a Transform) -> Transform {
        Transform {
            m: self.m * t.m,
            m_inv: t.m_inv * self.m_inv,
        }
    }
}

#[allow(non_snake_case)]
pub fn solve_linear_system2x2(A: &Matrix2<f32>, B: &Vector2f) -> Option<(f32, f32)> {
    let det = A.determinant();
    if det.abs() < 1e-10 {
        return None;
    }
    let x0 = (A[(1, 1)] * B[0] - A[(0, 1)] * B[1]) / det;
    let x1 = (A[(0, 0)] * B[1] - A[(1, 0)] * B[0]) / det;

    if x0.is_nan() || x1.is_nan() {
        return None;
    }
    return Some((x0, x1));
}

#[test]
fn test_normal_transform() {
    let t = Transform::new(Vector3f::new(0.0, 0.0, 0.0),
                           Vector3f::new(4.0, 5.0, 6.0),
                           4.0);
    let t_inv = t.inverse();

    let v = Vector3f::x();
    let n = Vector3f::y();
    println!("v = {}, n = {}", v, n);
    assert_eq!(v.dot(&n), 0.0);

    let v2 = &t * &v;
    let n2 = t_inv.transform_normal(&n);
    println!("v = {}, n = {}", v2, n2);
    relative_eq!(v2.dot(&n2), 0.0);
}
<commit_msg>Make sure we convert rotation angle to radians...<commit_after>use std::ops::Mul;
use na::{self, Affine3, Matrix2, Matrix4, Similarity3, U3};

use {gamma, Point3f, Vector2f, Vector3f};

#[derive(Debug, Clone)]
pub struct Transform {
    pub m: Matrix4<f32>,
    pub m_inv: Matrix4<f32>,
}

impl Transform {
    pub fn new(t: Vector3f, r: Vector3f, s: f32) -> Transform {
        Transform::from_similarity(&Similarity3::new(t, r, s))
    }

    pub fn from_similarity(s: &Similarity3<f32>) -> Transform {
        Transform {
            m: s.to_homogeneous(),
            m_inv: s.inverse().to_homogeneous(),
        }
    }

    pub fn rotate(angle: f32, v: Vector3f) -> Transform {
        Transform::new(na::zero(), v * angle.to_radians(), 1.0)
    }

    pub fn rot_x(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::x() * angle.to_radians(), 1.0)
    }

    pub fn rot_y(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::y() * angle.to_radians(), 1.0)
    }

    pub fn rot_z(angle: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::z() * angle.to_radians(), 1.0)
    }

    pub fn rot(ax: f32, ay: f32, az: f32) -> Transform {
        Transform::new(na::zero(), Vector3f::new(ax, ay, az), 1.0)
    }

    pub fn translate(t: Vector3f) -> Transform {
        Transform::new(t, na::zero(), 1.0)
    }

    pub fn translate_x(t: f32) -> Transform {
        Transform::new(Vector3f::x() * t, na::zero(), 1.0)
    }

    pub fn translate_y(t: f32) -> Transform {
        Transform::new(Vector3f::y() * t, na::zero(), 1.0)
    }

    pub fn translate_z(t: f32) -> Transform {
        Transform::new(Vector3f::z() * t, na::zero(), 1.0)
    }

    pub fn scale_uniform(s: f32) -> Transform {
        Transform::new(na::zero(), na::zero(), s)
    }

    pub fn scale(sx: f32, sy: f32, sz: f32) -> Transform {
        let mat = Matrix4::new_nonuniform_scaling(&Vector3f::new(sx, sy, sz));
        Transform {
            m: mat,
            m_inv: mat.try_inverse().unwrap(),
        }
    }

    pub fn inverse(&self) -> Self {
        Transform {
            m: self.m_inv,
            m_inv: self.m,
        }
    }

    /// Transform the given point using the given transformation and also return a vector of the
    /// absolute error introduced for each coordinate.
    pub fn transform_point(&self, p: &Point3f) -> (Point3f, Vector3f) {
        let (x, y, z) = (p.x, p.y, p.z);
        let tp = self * p;
        let m = self.m;
        let x_abs_sum =
            (m[(0, 0)] * x).abs() + (m[(0, 1)] * y).abs() + (m[(0, 2)] * z).abs() + m[(0, 3)].abs();
        let y_abs_sum =
            (m[(1, 0)] * x).abs() + (m[(1, 1)] * y).abs() + (m[(1, 2)] * z).abs() + m[(1, 3)].abs();
        let z_abs_sum =
            (m[(2, 0)] * x).abs() + (m[(2, 1)] * y).abs() + (m[(2, 2)] * z).abs() + m[(2, 3)].abs();
        let p_err = gamma(3) * Vector3f::new(x_abs_sum, y_abs_sum, z_abs_sum);

        (tp, p_err)
    }

    pub fn transform_point_with_error(
        &self,
        p: &Point3f,
        p_error: &Vector3f,
    ) -> (Point3f, Vector3f) {
        let (x, y, z) = (p.x, p.y, p.z);
        let tp = self * p;
        let m = self.m;
        let x_abs_err = (gamma(3) + 1.0) *
            ((m[(0, 0)] * p_error.x).abs() + (m[(0, 1)] * p_error.y).abs() +
                (m[(0, 2)] * p_error.z).abs()) +
            gamma(3) *
                ((m[(0, 0)] * x).abs() + (m[(0, 1)] * y).abs() + (m[(0, 2)] * z).abs() +
                    m[(0, 3)].abs());
        let y_abs_err = (gamma(3) + 1.0) *
            ((m[(1, 0)] * p_error.x).abs() + (m[(1, 1)] * p_error.y).abs() +
                (m[(1, 2)] * p_error.z).abs()) +
            gamma(3) *
                ((m[(1, 0)] * x).abs() + (m[(1, 1)] * y).abs() + (m[(1, 2)] * z).abs() +
                    m[(1, 3)].abs());
        let z_abs_err = (gamma(3) + 1.0) *
            ((m[(2, 0)] * p_error.x).abs() + (m[(2, 1)] * p_error.y).abs() +
                (m[(2, 2)] * p_error.z).abs()) +
            gamma(3) *
                ((m[(2, 0)] * x).abs() + (m[(2, 1)] * y).abs() + (m[(2, 2)] * z).abs() +
                    m[(2, 3)].abs());
        let p_err = Vector3f::new(x_abs_err, y_abs_err, z_abs_err);

        (tp, p_err)
    }

    /// Transform the given point using the given transformation and also return a vector of the
    /// absolute error introduced for each coordinate.
    pub fn transform_vector(&self, v: &Vector3f) -> (Vector3f, Vector3f) {
        let (x, y, z) = (v.x, v.y, v.z);
        let tv = self * v;
        let m = self.m;
        let x_abs_sum = na::abs(&(m[(0, 0)] * x)) + na::abs(&(m[(0, 1)] * y)) +
            na::abs(&(m[(0, 2)] * z)) + na::abs(&m[(0, 3)]);
        let y_abs_sum = na::abs(&(m[(1, 0)] * x)) + na::abs(&(m[(1, 1)] * y)) +
            na::abs(&(m[(1, 2)] * z)) + na::abs(&m[(1, 3)]);
        let z_abs_sum = na::abs(&(m[(2, 0)] * x)) + na::abs(&(m[(2, 1)] * y)) +
            na::abs(&(m[(2, 2)] * z)) + na::abs(&m[(2, 3)]);
        let v_err = gamma(3) * Vector3f::new(x_abs_sum, y_abs_sum, z_abs_sum);

        (tv, v_err)
    }

    pub fn transform_normal(&self, normal: &Vector3f) -> Vector3f {
        let m = self.m_inv.transpose();
        m.fixed_slice::<U3, U3>(0, 0) * *normal
    }
}

impl Default for Transform {
    fn default() -> Self {
        Transform {
            m: na::one(),
            m_inv: na::one(),
        }
    }
}

impl<'a, 'b> Mul<&'a Point3f> for &'b Transform {
    type Output = Point3f;

    fn mul(self, p: &'a Point3f) -> Point3f {
        let x = p.x;
        let y = p.y;
        let z = p.z;
        let xp = self.m[(0, 0)] * x + self.m[(0, 1)] * y + self.m[(0, 2)] * z + self.m[(0, 3)];
        let yp = self.m[(1, 0)] * x + self.m[(1, 1)] * y + self.m[(1, 2)] * z + self.m[(1, 3)];
        let zp = self.m[(2, 0)] * x + self.m[(2, 1)] * y + self.m[(2, 2)] * z + self.m[(2, 3)];
        let wp = self.m[(3, 0)] * x + self.m[(3, 1)] * y + self.m[(3, 2)] * z + self.m[(3, 3)];

        assert!(wp != 0.0);

        if wp == 1.0 {
            Point3f::new(xp, yp, zp)
        } else {
            Point3f::new(xp, yp, zp) / wp
        }
    }
}

impl<'a, 'b> Mul<&'a Vector3f> for &'b Transform {
    type Output = Vector3f;

    fn mul(self, v: &'a Vector3f) -> Vector3f {
        let x = v.x;
        let y = v.y;
        let z = v.z;

        Vector3f::new(
            self.m[(0, 0)] * x + self.m[(0, 1)] * y + self.m[(0, 2)] * z,
            self.m[(1, 0)] * x + self.m[(1, 1)] * y + self.m[(1, 2)] * z,
            self.m[(2, 0)] * x + self.m[(2, 1)] * y + self.m[(2, 2)] * z,
        )
    }
}

impl<'a, 'b> Mul<&'a Transform> for &'b Transform {
    type Output = Transform;

    fn mul(self, t: &'a Transform) -> Transform {
        Transform {
            m: self.m * t.m,
            m_inv: t.m_inv * self.m_inv,
        }
    }
}

#[allow(non_snake_case)]
pub fn solve_linear_system2x2(A: &Matrix2<f32>, B: &Vector2f) -> Option<(f32, f32)> {
    let det = A.determinant();
    if det.abs() < 1e-10 {
        return None;
    }
    let x0 = (A[(1, 1)] * B[0] - A[(0, 1)] * B[1]) / det;
    let x1 = (A[(0, 0)] * B[1] - A[(1, 0)] * B[0]) / det;

    if x0.is_nan() || x1.is_nan() {
        return None;
    }
    return Some((x0, x1));
}

#[test]
fn test_normal_transform() {
    let t = Transform::new(
        Vector3f::new(0.0, 0.0, 0.0),
        Vector3f::new(4.0, 5.0, 6.0),
        4.0,
    );
    let t_inv = t.inverse();

    let v = Vector3f::x();
    let n = Vector3f::y();
    println!("v = {}, n = {}", v, n);
    assert_eq!(v.dot(&n), 0.0);

    let v2 = &t * &v;
    let n2 = t_inv.transform_normal(&n);
    println!("v = {}, n = {}", v2, n2);
    relative_eq!(v2.dot(&n2), 0.0);
}
<|endoftext|>


<commit_before>
//! manage endpoint `/changes/`

use clap;
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// creat, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches) -> GGRResult<()> {
    let userquery = Query::from(y.values_of("userquery").unwrap());

    let configfile = try!(config::ConfigFile::discover(".", ".ggr.conf"));
    let config = config::Config::from_configfile(configfile);

    if ! config.is_valid() {
        return Err(GGRError::General("problem with configfile".to_string()));
    }

    let gerrit = Gerrit::new(config.get_base_url());

    let response_changes = gerrit.changes(Some(userquery.get_query()), None);

    match response_changes {
        Ok(changeinfos) => {
            for ci in changeinfos {
                println!("{}", ci);
            }
        },
        Err(x) => {
            return Err(x);
        }
    }

    Ok(())
}

#[derive(Clone)]
struct Query<'query> {
    query: Vec<&'query str>,
}

impl<'value> From<clap::Values<'value>> for Query<'value> {
    fn from(v: clap::Values<'value>) -> Query<'value> {
        let mut qb = Query::new();

        for (_, arg) in v.enumerate() {
            qb.from_str(&arg);
        }
        qb
    }
}

impl<'query> Query<'query> {
    pub fn new() -> Query<'query> {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn from_str(&mut self, x: &'query str) -> &mut Query<'query> {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<&'query str> {
        &self.query
    }
}
<commit_msg>changes: use better name for from_str<commit_after>
//! manage endpoint `/changes/`

use clap;
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// creat, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches) -> GGRResult<()> {
    let userquery = Query::from(y.values_of("userquery").unwrap());

    let configfile = try!(config::ConfigFile::discover(".", ".ggr.conf"));
    let config = config::Config::from_configfile(configfile);

    if ! config.is_valid() {
        return Err(GGRError::General("problem with configfile".to_string()));
    }

    let gerrit = Gerrit::new(config.get_base_url());

    let response_changes = gerrit.changes(Some(userquery.get_query()), None);

    match response_changes {
        Ok(changeinfos) => {
            for ci in changeinfos {
                println!("{}", ci);
            }
        },
        Err(x) => {
            return Err(x);
        }
    }

    Ok(())
}

#[derive(Clone)]
struct Query<'query> {
    query: Vec<&'query str>,
}

impl<'value> From<clap::Values<'value>> for Query<'value> {
    fn from(v: clap::Values<'value>) -> Query<'value> {
        let mut qb = Query::new();

        for (_, arg) in v.enumerate() {
            qb.add_str(arg);
        }
        qb
    }
}

impl<'query> Query<'query> {
    pub fn new() -> Query<'query> {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn add_str(&mut self, x: &'query str) -> &mut Query<'query> {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<&'query str> {
        &self.query
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use std::net;
    use mio::tcp;
    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl SocketOpt for tcp::TcpStream {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    impl SocketOpt for net::TcpStream {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use mio::tcp;
    use std::net;
    use std::io::Result;

    impl SocketOpt for tcp::TcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }

    impl SocketOpt for net::TcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use std::net::{SocketAddr, TcpListener as StdTcpListener, TcpStream as StdTcpStream};
    use mio::tcp::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    #[test]
    fn test_mio_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();

        let server = MioTcpListener::bind(&addr).unwrap();
        let addr = &format!("{}", server.local_addr().unwrap());

        let sock = MioTcpStream::connect(&addr.parse().unwrap()).unwrap();

        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }

    #[cfg(unix)]
    #[test]
    fn test_std_sock_opt() {
        let server = StdTcpListener::bind("127.0.0.1:0").unwrap();
        let addr = &format!("{}", server.local_addr().unwrap());

        let sock = StdTcpStream::connect(&addr.parse().unwrap()).unwrap();

        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }
}
<commit_msg>util: impl SocketOpt for std TcpStream<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use std::net::TcpStream as MioTcpStream;
    use mio::tcp::TcpStream as StdTcpStream;
    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl SocketOpt for MioTcpStream {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    impl SocketOpt for StdTcpStream {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use std::net::TcpStream as MioTcpStream;
    use mio::tcp::TcpStream as StdTcpStream;
    use std::io::Result;

    impl SocketOpt for MioTcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }

    impl SocketOpt for StdTcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use std::net::{SocketAddr, TcpListener as StdTcpListener, TcpStream as StdTcpStream};
    use mio::tcp::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    #[test]
    fn test_mio_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();

        let server = MioTcpListener::bind(&addr).unwrap();
        let addr = &format!("{}", server.local_addr().unwrap());

        let sock = MioTcpStream::connect(&addr.parse().unwrap()).unwrap();

        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }

    #[cfg(unix)]
    #[test]
    fn test_std_sock_opt() {
        let server = StdTcpListener::bind("127.0.0.1:0").unwrap();
        let addr: SocketAddr = format!("{}", server.local_addr().unwrap()).parse().unwrap();

        let sock = StdTcpStream::connect(addr).unwrap();

        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }
}
<|endoftext|>