<commit_before>#![allow(non_snake_case_functions)]

use std::u8;
use std::str::from_utf8;
use std::char::from_u32;
use std::char;
use std::u32;

// TODO: Fix this when the following issue is fixed:
//   https://github.com/mozilla/rust/issues/4334
static X_U8: u8 = 'x' as u8;
static A_U8: u8 = 'a' as u8;
static B_U8: u8 = 'b' as u8;
static F_U8: u8 = 'f' as u8;
static N_U8: u8 = 'n' as u8;
static R_U8: u8 = 'r' as u8;
static T_U8: u8 = 't' as u8;
static U_U8: u8 = 'u' as u8;
static V_U8: u8 = 'v' as u8;
static ZERO_U8: u8 = '0' as u8;
static SINGLE_QUOTE_U8: u8 = '\'' as u8;
static DOUBLE_QUOTE_U8: u8 = '"' as u8;
static SLASH_U8: u8 = '\\' as u8;

// See:
//   http://en.wikipedia.org/wiki/Escape_sequences_in_C
//   http://en.cppreference.com/w/cpp/language/escape
// No question mark escape supported because there are no trigraphs in PEG.
pub fn unescape( input: &[u8] ) -> Vec<u8> {
  let mut final_bytes = Vec::new();
  let mut index = 0;
  loop {
    // TODO: support \u12345678, not just \u1234
    match input.slice_from( index ) {
      [ SLASH_U8, U_U8, c1, c2, c3, c4, .. ]
          if isHex( c1 ) && isHex( c2 ) && isHex( c3 ) && isHex( c4 ) => {
        final_bytes = addFourBytesAsCodepoint( final_bytes, [c1, c2, c3, c4] );
        index += 6;
      }
      [ SLASH_U8, X_U8, c1, c2, .. ]
          if isHex( c1 ) && isHex( c2 ) => {
        final_bytes = addTwoBytesAsHex( final_bytes, [c1, c2] );
        index += 4;
      }
      [ SLASH_U8, c1, c2, c3, .. ]
          if isOctal( c1 ) && isOctal( c2 ) && isOctal( c3 ) => {
        final_bytes = addThreeBytesAsOctal( final_bytes, [c1, c2, c3] );
        index += 4;
      }
      [ SLASH_U8, c, .. ] => {
        final_bytes = addEscapedByte( final_bytes, c );
        index += 2;
      }
      [ c, .. ] => {
        final_bytes.push( c );
        index += 1;
      }
      [] => break,
    }
  }

  return final_bytes;
}

pub fn unescapeString( input: &str ) -> String {
  from_utf8( unescape( input.as_bytes() ).as_slice() ).unwrap().to_string()
}

fn isOctal( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 8 )
}

fn isHex( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 16 )
}

fn addFourBytesAsCodepoint( mut input: Vec<u8>, bytes: [u8, ..4] ) -> Vec<u8> {
  match u32::parse_bytes( bytes, 16 ) {
    Some( x ) => match from_u32( x ) {
      Some( character ) => {
        let utf8chars: &mut [u8] = [0, ..4];
        let num_written = character.encode_utf8( utf8chars );
        for i in range( 0, num_written ) {
          input.push( *utf8chars.get( i ).unwrap() );
        }
      },
      _ => fail!( "Invalid unicode code point: {}", x )
    },
    _ => fail!( "Invalid unicode escape sequence: \\\\u{}{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap(),
                bytes.get( 3 ).unwrap() )
  }
  input
}

fn addTwoBytesAsHex( mut input: Vec<u8>, bytes: [u8, ..2] ) -> Vec<u8> {
  match u8::parse_bytes( bytes, 16 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid hex escape sequence: \\\\x{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap() )
  }
  input
}

fn addThreeBytesAsOctal( mut input: Vec<u8>, bytes: [u8, ..3] ) -> Vec<u8> {
  match u8::parse_bytes( bytes, 8 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid octal escape sequence: \\\\{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap() )
  }
  input
}

fn addEscapedByte( mut input: Vec<u8>, byte: u8 ) -> Vec<u8> {
  let unescaped_char = match byte {
    A_U8            => Some( '\x07' as u8 ),
    B_U8            => Some( '\x08' as u8 ),
    F_U8            => Some( '\x0c' as u8 ),
    N_U8            => Some( '\n' as u8   ),
    R_U8            => Some( '\r' as u8   ),
    T_U8            => Some( '\t' as u8   ),
    V_U8            => Some( '\x0b' as u8 ),
    ZERO_U8         => Some( '\0' as u8   ),
    SINGLE_QUOTE_U8 => Some( '\'' as u8   ),
    DOUBLE_QUOTE_U8 => Some( '"' as u8    ),
    SLASH_U8        => Some( '\\' as u8   ),
    _               => None
  };

  match unescaped_char {
    Some( x ) => input.push( x ),
    None => {
      input.push( '\\' as u8 );
      input.push( byte )
    }
  };
  input
}

#[cfg(test)]
mod tests {
  use super::{unescape};

  fn vecBytes( input: &'static str ) -> Vec<u8> {
    Vec::from_slice( input.as_bytes() )
  }

  #[test]
  fn unescape_Nothing() {
    assert_eq!( unescape( b"foobar" ),         vecBytes( "foobar" ) );
    assert_eq!( unescape( b"123"    ),         vecBytes( "123" )    );
    assert_eq!( unescape( "葉".as_bytes() ),   vecBytes( "葉" )     );
    assert_eq!( unescape( "a葉8".as_bytes() ), vecBytes( "a葉8" )   );
  }

  #[test]
  fn unescape_LooksLikeEscapeButNot() {
    assert_eq!( unescape( b"\\z" ), vecBytes( "\\z" ) );
    assert_eq!( unescape( b"a\\zg" ), vecBytes( "a\\zg" ) );
  }

  #[test]
  fn unescape_SingleCharEscapeCodes() {
    assert_eq!( unescape( b"\\a"  ), vecBytes( "\x07" ) );
    assert_eq!( unescape( b"\\b"  ), vecBytes( "\x08" ) );
    assert_eq!( unescape( b"\\f"  ), vecBytes( "\x0c" ) );
    assert_eq!( unescape( b"\\n"  ), vecBytes( "\n" )   );
    assert_eq!( unescape( b"\\r"  ), vecBytes( "\r" )   );
    assert_eq!( unescape( b"\\t"  ), vecBytes( "\t" )   );
    assert_eq!( unescape( b"\\v"  ), vecBytes( "\x0b" ) );
    assert_eq!( unescape( b"\\0"  ), vecBytes( "\0" )   );
    assert_eq!( unescape( b"\\'"  ), vecBytes( "\'" )   );
    assert_eq!( unescape( b"\\\"" ), vecBytes( "\"" )   );
    assert_eq!( unescape( b"\\\\" ), vecBytes( "\\" )   );
  }

  #[test]
  fn unescape_MultipleSingleCharEscapeCodes() {
    assert_eq!( unescape( b"\\r\\n" ), vecBytes( "\r\n" ) );
    assert_eq!( unescape( b"\\\\\\\\" ), vecBytes( "\\\\" ) );
  }

  #[test]
  fn unescape_HexEscape() {
    assert_eq!( unescape( b"\\x4E" ), vecBytes( "N" ) );
    assert_eq!( unescape( b"\\x4e" ), vecBytes( "N" ) );
    assert_eq!( unescape( b"\\x00\\x01" ), vec!( 0, 1 ) );
  }

  #[test]
  fn unescape_HexEscape_Bad() {
    assert_eq!( unescape( b"\\x" ), vecBytes( "\\x" ) );
    assert_eq!( unescape( b"\\xgg" ), vecBytes( "\\xgg" ) );
  }

  #[test]
  fn unescape_UnicodeEscape() {
    assert_eq!( unescape( b"\\u0106" ), vecBytes( "Ć" ) );
    assert_eq!( unescape( b"\\u0106\\u04E8" ), vecBytes( "ĆӨ" ) );
    assert_eq!( unescape( b"\\u81EA\\u7531" ), vecBytes( "自由" ) );
  }

  #[test]
  fn unescape_UnicodeEscape_Bad() {
    assert_eq!( unescape( b"\\u" ), vecBytes( "\\u" ) );
    assert_eq!( unescape( b"\\u01x" ), vecBytes( "\\u01x" ) );
  }

  #[test]
  fn unescape_OctalEscape() {
    assert_eq!( unescape( b"\\001" ), vec!( 1 ) );
    assert_eq!( unescape( b"\\157" ), vec!( 111 ) );
  }
}
<commit_msg>More byte literal usage<commit_after>#![allow(non_snake_case_functions)]

use std::u8;
use std::str::from_utf8;
use std::char::from_u32;
use std::char;
use std::u32;

// See:
//   http://en.wikipedia.org/wiki/Escape_sequences_in_C
//   http://en.cppreference.com/w/cpp/language/escape
// No question mark escape supported because there are no trigraphs in PEG.
pub fn unescape( input: &[u8] ) -> Vec<u8> {
  let mut final_bytes = Vec::new();
  let mut index = 0;
  loop {
    // TODO: support \u12345678, not just \u1234
    match input.slice_from( index ) {
      [ b'\\', b'u', c1, c2, c3, c4, .. ]
          if isHex( c1 ) && isHex( c2 ) && isHex( c3 ) && isHex( c4 ) => {
        final_bytes = addFourBytesAsCodepoint( final_bytes, [c1, c2, c3, c4] );
        index += 6;
      }
      [ b'\\', b'x', c1, c2, .. ]
          if isHex( c1 ) && isHex( c2 ) => {
        final_bytes = addTwoBytesAsHex( final_bytes, [c1, c2] );
        index += 4;
      }
      [ b'\\', c1, c2, c3, .. ]
          if isOctal( c1 ) && isOctal( c2 ) && isOctal( c3 ) => {
        final_bytes = addThreeBytesAsOctal( final_bytes, [c1, c2, c3] );
        index += 4;
      }
      [ b'\\', c, .. ] => {
        final_bytes = addEscapedByte( final_bytes, c );
        index += 2;
      }
      [ c, .. ] => {
        final_bytes.push( c );
        index += 1;
      }
      [] => break,
    }
  }

  return final_bytes;
}

pub fn unescapeString( input: &str ) -> String {
  from_utf8( unescape( input.as_bytes() ).as_slice() ).unwrap().to_string()
}

fn isOctal( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 8 )
}

fn isHex( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 16 )
}

fn addFourBytesAsCodepoint( mut input: Vec<u8>, bytes: [u8, ..4] ) -> Vec<u8> {
  match u32::parse_bytes( bytes, 16 ) {
    Some( x ) => match from_u32( x ) {
      Some( character ) => {
        let utf8chars: &mut [u8] = [0, ..4];
        let num_written = character.encode_utf8( utf8chars );
        for i in range( 0, num_written ) {
          input.push( *utf8chars.get( i ).unwrap() );
        }
      },
      _ => fail!( "Invalid unicode code point: {}", x )
    },
    _ => fail!( r"Invalid unicode escape sequence: \u{}{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap(),
                bytes.get( 3 ).unwrap() )
  }
  input
}

fn addTwoBytesAsHex( mut input: Vec<u8>, bytes: [u8, ..2] ) -> Vec<u8> {
  match u8::parse_bytes( bytes, 16 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( r"Invalid hex escape sequence: \x{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap() )
  }
  input
}

fn addThreeBytesAsOctal( mut input: Vec<u8>, bytes: [u8, ..3] ) -> Vec<u8> {
  match u8::parse_bytes( bytes, 8 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( r"Invalid octal escape sequence: \{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap() )
  }
  input
}

fn addEscapedByte( mut input: Vec<u8>, byte: u8 ) -> Vec<u8> {
  let unescaped_char = match byte {
    b'a'  => Some( b'\x07' ),
    b'b'  => Some( b'\x08' ),
    b'f'  => Some( b'\x0c' ),
    b'n'  => Some( b'\n'   ),
    b'r'  => Some( b'\r'   ),
    b't'  => Some( b'\t'   ),
    b'v'  => Some( b'\x0b' ),
    b'0'  => Some( b'\0'   ),
    b'\'' => Some( b'\''   ),
    b'"'  => Some( b'"'    ),
    b'\\' => Some( b'\\'   ),
    _     => None
  };

  match unescaped_char {
    Some( x ) => input.push( x ),
    None => {
      input.push( b'\\' );
      input.push( byte )
    }
  };
  input
}

#[cfg(test)]
mod tests {
  use super::{unescape};

  fn vecBytes( input: &'static str ) -> Vec<u8> {
    Vec::from_slice( input.as_bytes() )
  }

  #[test]
  fn unescape_Nothing() {
    assert_eq!( unescape( b"foobar" ),         vecBytes( "foobar" ) );
    assert_eq!( unescape( b"123"    ),         vecBytes( "123" )    );
    assert_eq!( unescape( "葉".as_bytes() ),   vecBytes( "葉" )     );
    assert_eq!( unescape( "a葉8".as_bytes() ), vecBytes( "a葉8" )   );
  }

  #[test]
  fn unescape_LooksLikeEscapeButNot() {
    assert_eq!( unescape( b"\\z" ), vecBytes( "\\z" ) );
    assert_eq!( unescape( b"a\\zg" ), vecBytes( "a\\zg" ) );
  }

  #[test]
  fn unescape_SingleCharEscapeCodes() {
    assert_eq!( unescape( b"\\a"  ), vecBytes( "\x07" ) );
    assert_eq!( unescape( b"\\b"  ), vecBytes( "\x08" ) );
    assert_eq!( unescape( b"\\f"  ), vecBytes( "\x0c" ) );
    assert_eq!( unescape( b"\\n"  ), vecBytes( "\n" )   );
    assert_eq!( unescape( b"\\r"  ), vecBytes( "\r" )   );
    assert_eq!( unescape( b"\\t"  ), vecBytes( "\t" )   );
    assert_eq!( unescape( b"\\v"  ), vecBytes( "\x0b" ) );
    assert_eq!( unescape( b"\\0"  ), vecBytes( "\0" )   );
    assert_eq!( unescape( b"\\'"  ), vecBytes( "\'" )   );
    assert_eq!( unescape( b"\\\"" ), vecBytes( "\"" )   );
    assert_eq!( unescape( b"\\\\" ), vecBytes( "\\" )   );
  }

  #[test]
  fn unescape_MultipleSingleCharEscapeCodes() {
    assert_eq!( unescape( b"\\r\\n" ), vecBytes( "\r\n" ) );
    assert_eq!( unescape( b"\\\\\\\\" ), vecBytes( "\\\\" ) );
  }

  #[test]
  fn unescape_HexEscape() {
    assert_eq!( unescape( b"\\x4E" ), vecBytes( "N" ) );
    assert_eq!( unescape( b"\\x4e" ), vecBytes( "N" ) );
    assert_eq!( unescape( b"\\x00\\x01" ), vec!( 0, 1 ) );
  }

  #[test]
  fn unescape_HexEscape_Bad() {
    assert_eq!( unescape( b"\\x" ), vecBytes( "\\x" ) );
    assert_eq!( unescape( b"\\xgg" ), vecBytes( "\\xgg" ) );
  }

  #[test]
  fn unescape_UnicodeEscape() {
    assert_eq!( unescape( b"\\u0106" ), vecBytes( "Ć" ) );
    assert_eq!( unescape( b"\\u0106\\u04E8" ), vecBytes( "ĆӨ" ) );
    assert_eq!( unescape( b"\\u81EA\\u7531" ), vecBytes( "自由" ) );
  }

  #[test]
  fn unescape_UnicodeEscape_Bad() {
    assert_eq!( unescape( b"\\u" ), vecBytes( "\\u" ) );
    assert_eq!( unescape( b"\\u01x" ), vecBytes( "\\u01x" ) );
  }

  #[test]
  fn unescape_OctalEscape() {
    assert_eq!( unescape( b"\\001" ), vec!( 1 ) );
    assert_eq!( unescape( b"\\157" ), vec!( 111 ) );
  }
}
<|endoftext|>


<commit_before>use std::io::{Write, Result};
use super::super::representation::Representation;

pub enum Definition {
    Record(String),
    Enum(String),
    Function(String),
}

impl Representation for Definition {
    fn write_representation(&self, writer: &mut Write) -> Result<()> {
        match *self {
            Definition::Record(ref name) => {
                write!(writer, "type alias {}", name)
            },

            Definition::Enum(ref name) => {
                write!(writer, "type {}", name)
            },

            Definition::Function(ref name) => {
                write!(writer, "{} =", name)
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::representation::Representation;
    use super::*;

    #[test]
    fn record_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Record(String::from("TestRecord"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..21], b"type alias TestRecord"[..]);
    }

    #[test]
    fn enum_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Enum(String::from("TestEnum"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..13], b"type TestEnum"[..]);
    }

    #[test]
    fn function_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Function(String::from("TestFunction"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..14], b"TestFunction ="[..]);
    }
}
<commit_msg>Refactor Definitions into a struct<commit_after>use std::io::{Write, Result};
use super::super::representation::Representation;

pub struct Definition {
    name: String,
    definition_type: DefinitionType,
}

pub enum DefinitionType {
    Record,
    Enum,
    Function,
}

impl Definition {
    #[allow(non_snake_case)]
    pub fn Record<S>(name: S) -> Definition where S: Into<String> {
        Definition { name: name.into(), definition_type: DefinitionType::Record }
    }

    #[allow(non_snake_case)]
    pub fn Enum<S>(name: S) -> Definition where S: Into<String> {
        Definition { name: name.into(), definition_type: DefinitionType::Enum }
    }

    #[allow(non_snake_case)]
    pub fn Function<S>(name: S) -> Definition where S: Into<String> {
        Definition { name: name.into(), definition_type: DefinitionType::Function }
    }
}

impl Representation for Definition {
    fn write_representation(&self, writer: &mut Write) -> Result<()> {
        match self.definition_type {
            DefinitionType::Record => {
                write!(writer, "type alias {}", self.name)
            },

            DefinitionType::Enum => {
                write!(writer, "type {}", self.name)
            },

            DefinitionType::Function => {
                write!(writer, "{} =", self.name)
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::representation::Representation;
    use super::*;

    #[test]
    fn record_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Record(String::from("TestRecord"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..21], b"type alias TestRecord"[..]);
    }

    #[test]
    fn enum_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Enum(String::from("TestEnum"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..13], b"type TestEnum"[..]);
    }

    #[test]
    fn function_should_write_it_self() {
        let mut output = Vec::new();
        let definition = Definition::Function(String::from("TestFunction"));

        definition.write_representation(&mut output).unwrap();

        assert_eq!(output[0..14], b"TestFunction ="[..]);
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

use super::color::{White, Black};
use super::piece::{mod, Piece, WK, WR, BK, BR};
use super::square::{Square,File,Rank};
use super::moves::{Move,Plies};
use super::pos::{Position,Kingside,Queenside};

pub fn make_move(mut p: Position, m: &Move) -> Position {
    make_move_mut(&mut p, m);
    p
}

pub fn make_move_mut(p: &mut Position, m: &Move) {
    let from = m.from();
    let to = m.to();
    let curr_piece = p.at(from).unwrap();

    if m.is_capture() || m.is_en_passant() || curr_piece.piece_type() == piece::Type::Pawn {
        p.set_ply_count_mut(Plies(0));
    } else {
        let Plies(temp) = p.ply_count();
        p.set_ply_count_mut(Plies(temp+1));
    }

    if m.is_castle() {

        let castle_color = match from.rank() {
            Rank(0) => White,
            Rank(7) => Black,
            _ => panic!(),
        };
        let castle_side = match to.file() {
            File(2) => Queenside,
            File(6) => Kingside,
            _ => panic!(),
        };

        let (rook_from, rook_to) = match (castle_color, castle_side) {
            (White, Kingside ) => (Square::new(File(7),Rank(0)), Square::new(File(5),Rank(0))),
            (White, Queenside) => (Square::new(File(0),Rank(0)), Square::new(File(3),Rank(0))),
            (Black, Kingside ) => (Square::new(File(7),Rank(7)), Square::new(File(5),Rank(7))),
            (Black, Queenside) => (Square::new(File(0),Rank(7)), Square::new(File(3),Rank(7))),
        };

        p.remove_at_mut(from);
        p.set_at_mut(to, curr_piece);
        let curr_rook = p.at(rook_from).unwrap();
        p.remove_at_mut(rook_from);
        p.set_at_mut(rook_to, curr_rook);

    } else if m.is_en_passant() {
        //TODO implement en passant
        unimplemented!();
    } else if m.is_promote() {
        //no en passant
        p.set_en_passant_mut(None);

        //change the board and promote
        if m.is_capture() {
            p.remove_at_mut(to);
        }
        p.remove_at_mut(from);
        p.set_at_mut(to, Piece::new(curr_piece.color(), m.promote().unwrap()));
    } else {
        //TODO set enpassant

        //change the board
        if m.is_capture() {
            p.remove_at_mut(to);
        }
        p.remove_at_mut(from);
        p.set_at_mut(to, curr_piece);
    }

    //castling
    if p.at(Square::new(File(4),Rank(0))) != Some(WK) {
        p.set_castle_mut(Queenside, White, false);
        p.set_castle_mut(Kingside , White, false);
    }
    if p.at(Square::new(File(0),Rank(0))) != Some(WR) {
        p.set_castle_mut(Queenside, White, false);
    }
    if p.at(Square::new(File(7),Rank(0))) != Some(WR) {
        p.set_castle_mut(Kingside , White, false);
    }
    if p.at(Square::new(File(4),Rank(7))) != Some(BK) {
        p.set_castle_mut(Queenside, Black, false);
        p.set_castle_mut(Kingside , Black, false);
    }
    if p.at(Square::new(File(0),Rank(7))) != Some(BR) {
        p.set_castle_mut(Queenside, Black, false);
    }
    if p.at(Square::new(File(7),Rank(7))) != Some(BR) {
        p.set_castle_mut(Kingside , Black, false);
    }

    let next_color = p.side_to_move().invert();
    p.set_side_to_move_mut(next_color);
}
<commit_msg>Reset en passant after castling.<commit_after>#![allow(unused_variables)]

use super::color::{White, Black};
use super::piece::{mod, Piece, WK, WR, BK, BR};
use super::square::{Square,File,Rank};
use super::moves::{Move,Plies};
use super::pos::{Position,Kingside,Queenside};

pub fn make_move(mut p: Position, m: &Move) -> Position {
    make_move_mut(&mut p, m);
    p
}

pub fn make_move_mut(p: &mut Position, m: &Move) {
    let from = m.from();
    let to = m.to();
    let curr_piece = p.at(from).unwrap();

    if m.is_capture() || m.is_en_passant() || curr_piece.piece_type() == piece::Type::Pawn {
        p.set_ply_count_mut(Plies(0));
    } else {
        let Plies(temp) = p.ply_count();
        p.set_ply_count_mut(Plies(temp+1));
    }

    if m.is_castle() {

        //no en passant
        p.set_en_passant_mut(None);

        let castle_color = match from.rank() {
            Rank(0) => White,
            Rank(7) => Black,
            _ => panic!(),
        };
        let castle_side = match to.file() {
            File(2) => Queenside,
            File(6) => Kingside,
            _ => panic!(),
        };

        let (rook_from, rook_to) = match (castle_color, castle_side) {
            (White, Kingside ) => (Square::new(File(7),Rank(0)), Square::new(File(5),Rank(0))),
            (White, Queenside) => (Square::new(File(0),Rank(0)), Square::new(File(3),Rank(0))),
            (Black, Kingside ) => (Square::new(File(7),Rank(7)), Square::new(File(5),Rank(7))),
            (Black, Queenside) => (Square::new(File(0),Rank(7)), Square::new(File(3),Rank(7))),
        };

        p.remove_at_mut(from);
        p.set_at_mut(to, curr_piece);
        let curr_rook = p.at(rook_from).unwrap();
        p.remove_at_mut(rook_from);
        p.set_at_mut(rook_to, curr_rook);

    } else if m.is_en_passant() {
        //TODO implement en passant
        unimplemented!();
    } else if m.is_promote() {
        //no en passant
        p.set_en_passant_mut(None);

        //change the board and promote
        if m.is_capture() {
            p.remove_at_mut(to);
        }
        p.remove_at_mut(from);
        p.set_at_mut(to, Piece::new(curr_piece.color(), m.promote().unwrap()));
    } else {
        //TODO set enpassant

        //change the board
        if m.is_capture() {
            p.remove_at_mut(to);
        }
        p.remove_at_mut(from);
        p.set_at_mut(to, curr_piece);
    }

    //castling
    if p.at(Square::new(File(4),Rank(0))) != Some(WK) {
        p.set_castle_mut(Queenside, White, false);
        p.set_castle_mut(Kingside , White, false);
    }
    if p.at(Square::new(File(0),Rank(0))) != Some(WR) {
        p.set_castle_mut(Queenside, White, false);
    }
    if p.at(Square::new(File(7),Rank(0))) != Some(WR) {
        p.set_castle_mut(Kingside , White, false);
    }
    if p.at(Square::new(File(4),Rank(7))) != Some(BK) {
        p.set_castle_mut(Queenside, Black, false);
        p.set_castle_mut(Kingside , Black, false);
    }
    if p.at(Square::new(File(0),Rank(7))) != Some(BR) {
        p.set_castle_mut(Queenside, Black, false);
    }
    if p.at(Square::new(File(7),Rank(7))) != Some(BR) {
        p.set_castle_mut(Kingside , Black, false);
    }

    let next_color = p.side_to_move().invert();
    p.set_side_to_move_mut(next_color);
}
<|endoftext|>


<commit_before>use std::ptr;

use gc::swiper::CardIdx;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::{Address, Region};

#[derive(Clone)]
pub struct CardTable {
    // card table boundaries for old gen (not young gen)
    // table is actually larger but we shouldn't need
    // to touch the rest
    start: Address,
    end: Address,

    // contiguous region with old generation and large space
    old_and_large: Region,

    // end of old generation and start of large space
    old_end: Address,

    // number of cards in heap_size
    cards_in_heap: usize,
}

impl CardTable {
    pub fn new(
        start: Address,
        end: Address,
        old_and_large: Region,
        old_end: Address,
        heap_size: usize,
    ) -> CardTable {
        // only keep track of card table for old gen,
        // just ignore the card table for the young gen
        let start = start.offset(heap_size >> CARD_SIZE_BITS);

        assert!(old_and_large.contains(old_end));

        let card = CardTable {
            start: start,
            end: end,
            old_and_large: old_and_large,
            old_end: old_end,
            cards_in_heap: heap_size / CARD_SIZE,
        };

        // reset card table to all 1's
        card.reset();

        card
    }

    // reset card table entries to 1 (not dirty)
    fn reset(&self) {
        let size = self.size();

        unsafe {
            ptr::write_bytes(self.start.to_mut_ptr::<u8>(), 1, size);
        }
    }

    // reset cards for memory region to 1 (not dirty)
    pub fn reset_region(&self, start: Address, end: Address) {
        let start_idx = self.card_idx(start).to_usize();
        let end_idx = self.card_idx(end.align_card()).to_usize();

        for card_idx in start_idx..end_idx {
            self.set(card_idx.into(), CardEntry::Clean);
        }
    }

    // reset cards for address to 1 (not dirty)
    pub fn reset_addr(&self, addr: Address) {
        let card_idx = self.card_idx(addr);
        self.set(card_idx, CardEntry::Clean);
    }

    fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    // visits all dirty cards in region
    pub fn visit_dirty_in_old<F>(&self, start: Address, end: Address, mut f: F)
    where
        F: FnMut(CardIdx),
    {
        assert!(end >= self.old_and_large.start && end <= self.old_end);
        let (start_card_idx, end_card_idx) = self.card_indices(start, end.align_card());

        for card_idx in start_card_idx..end_card_idx {
            if self.get(card_idx.into()).is_dirty() {
                f(card_idx.into());
            }
        }
    }

    pub fn is_dirty(&self, addr: Address) -> bool {
        let card_idx = self.card_idx(addr);
        self.get(card_idx) == CardEntry::Dirty
    }

    pub fn get(&self, card: CardIdx) -> CardEntry {
        let card = self.index_from_card_idx(card);
        let ptr = self.start.offset(card);
        debug_assert!(ptr < self.end);

        let val: u8 = unsafe { *ptr.to_ptr() };

        if val == 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        }
    }

    pub fn set(&self, card: CardIdx, entry: CardEntry) {
        let card = self.index_from_card_idx(card);
        let ptr = self.start.offset(card);
        debug_assert!(ptr < self.end);

        let val: u8 = match entry {
            CardEntry::Clean => 1,
            CardEntry::Dirty => 0,
        };

        unsafe {
            *ptr.to_mut_ptr() = val;
        }
    }

    fn index_from_card_idx(&self, card: CardIdx) -> usize {
        let card = card.to_usize();
        assert!(card < 3 * self.cards_in_heap);
        card
    }

    #[inline(always)]
    pub fn is_aligned(&self, addr: Address) -> bool {
        (addr.offset_from(self.old_and_large.start) & (CARD_SIZE - 1)) == 0
    }

    #[inline(always)]
    pub fn to_address(&self, card: CardIdx) -> Address {
        let card = self.index_from_card_idx(card);
        self.old_and_large.start.offset(card << CARD_SIZE_BITS)
    }

    #[inline(always)]
    pub fn card_idx(&self, addr: Address) -> CardIdx {
        debug_assert!(self.old_and_large.contains(addr));
        let idx = addr.offset_from(self.old_and_large.start) >> CARD_SIZE_BITS;

        idx.into()
    }

    #[inline(always)]
    pub fn card_indices(&self, start: Address, end: Address) -> (usize, usize) {
        assert!(end >= start);

        let card_start = self.card_idx(start);
        let card_end = self.card_idx(end);

        (card_start.to_usize(), card_end.to_usize())
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum CardEntry {
    Clean,
    Dirty,
}

impl CardEntry {
    pub fn is_clean(self) -> bool {
        self == CardEntry::Clean
    }

    pub fn is_dirty(self) -> bool {
        self == CardEntry::Dirty
    }
}
<commit_msg>use write_bytes when cleaning cards<commit_after>use std::ptr;

use gc::swiper::CardIdx;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::{Address, Region};

#[derive(Clone)]
pub struct CardTable {
    // card table boundaries for old gen (not young gen)
    // table is actually larger but we shouldn't need
    // to touch the rest
    start: Address,
    end: Address,

    // contiguous region with old generation and large space
    old_and_large: Region,

    // end of old generation and start of large space
    old_end: Address,

    // number of cards in heap_size
    cards_in_heap: usize,
}

impl CardTable {
    pub fn new(
        start: Address,
        end: Address,
        old_and_large: Region,
        old_end: Address,
        heap_size: usize,
    ) -> CardTable {
        // only keep track of card table for old gen,
        // just ignore the card table for the young gen
        let start = start.offset(heap_size >> CARD_SIZE_BITS);

        assert!(old_and_large.contains(old_end));

        let card = CardTable {
            start: start,
            end: end,
            old_and_large: old_and_large,
            old_end: old_end,
            cards_in_heap: heap_size / CARD_SIZE,
        };

        // reset card table to all 1's
        card.reset();

        card
    }

    // reset card table entries to 1 (not dirty)
    fn reset(&self) {
        let size = self.size();

        unsafe {
            ptr::write_bytes(self.start.to_mut_ptr::<u8>(), 1, size);
        }
    }

    // reset cards for memory region to 1 (not dirty)
    pub fn reset_region(&self, start: Address, end: Address) {
        let start_idx = self.card_idx(start).to_usize();
        let end_idx = self.card_idx(end.align_card()).to_usize();

        let start = self.start.offset(start_idx);
        let size = end_idx - start_idx;

        unsafe {
            ptr::write_bytes(start.to_mut_ptr::<u8>(), 1, size);
        }
    }

    // reset cards for address to 1 (not dirty)
    pub fn reset_addr(&self, addr: Address) {
        let card_idx = self.card_idx(addr);
        self.set(card_idx, CardEntry::Clean);
    }

    fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    // visits all dirty cards in region
    pub fn visit_dirty_in_old<F>(&self, start: Address, end: Address, mut f: F)
    where
        F: FnMut(CardIdx),
    {
        assert!(end >= self.old_and_large.start && end <= self.old_end);
        let (start_card_idx, end_card_idx) = self.card_indices(start, end.align_card());

        for card_idx in start_card_idx..end_card_idx {
            if self.get(card_idx.into()).is_dirty() {
                f(card_idx.into());
            }
        }
    }

    pub fn is_dirty(&self, addr: Address) -> bool {
        let card_idx = self.card_idx(addr);
        self.get(card_idx) == CardEntry::Dirty
    }

    pub fn get(&self, card: CardIdx) -> CardEntry {
        let card = self.index_from_card_idx(card);
        let ptr = self.start.offset(card);
        debug_assert!(ptr < self.end);

        let val: u8 = unsafe { *ptr.to_ptr() };

        if val == 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        }
    }

    pub fn set(&self, card: CardIdx, entry: CardEntry) {
        let card = self.index_from_card_idx(card);
        let ptr = self.start.offset(card);
        debug_assert!(ptr < self.end);

        let val: u8 = match entry {
            CardEntry::Clean => 1,
            CardEntry::Dirty => 0,
        };

        unsafe {
            *ptr.to_mut_ptr() = val;
        }
    }

    fn index_from_card_idx(&self, card: CardIdx) -> usize {
        let card = card.to_usize();
        assert!(card < 3 * self.cards_in_heap);
        card
    }

    #[inline(always)]
    pub fn is_aligned(&self, addr: Address) -> bool {
        (addr.offset_from(self.old_and_large.start) & (CARD_SIZE - 1)) == 0
    }

    #[inline(always)]
    pub fn to_address(&self, card: CardIdx) -> Address {
        let card = self.index_from_card_idx(card);
        self.old_and_large.start.offset(card << CARD_SIZE_BITS)
    }

    #[inline(always)]
    pub fn card_idx(&self, addr: Address) -> CardIdx {
        debug_assert!(self.old_and_large.contains(addr));
        let idx = addr.offset_from(self.old_and_large.start) >> CARD_SIZE_BITS;

        idx.into()
    }

    #[inline(always)]
    pub fn card_indices(&self, start: Address, end: Address) -> (usize, usize) {
        assert!(end >= start);

        let card_start = self.card_idx(start);
        let card_end = self.card_idx(end);

        (card_start.to_usize(), card_end.to_usize())
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum CardEntry {
    Clean,
    Dirty,
}

impl CardEntry {
    pub fn is_clean(self) -> bool {
        self == CardEntry::Clean
    }

    pub fn is_dirty(self) -> bool {
        self == CardEntry::Dirty
    }
}
<|endoftext|>


<commit_before>// Module for reading sprides and saving them in a HashMap

use std::collections::HashMap;
use piston_window::*;
use io::sprite::Sprite;

/// HashMap for all given sprites
pub struct SpriteMap {
    pub map: HashMap<&'static str, Sprite>,
}

impl SpriteMap {
    /// Initialize the SpriteMap with given window, fills Map with all Sprites
    pub fn init(mut w: &mut PistonWindow) -> Self {
        let mut map2: HashMap<&'static str, Sprite> = HashMap::new();
        for i in SPRITES {
            map2.insert(i.image,
                        Sprite::fill_sprite(i.image, i.size_x as u32, i.size_y as u32,i.dur as u64, i.once, w));
        }

        SpriteMap { map: map2 }

    }

    /// creates empty SpriteMap
    pub fn new() -> Self {
        SpriteMap { map: HashMap::new() }
    }
    pub fn get_sprite(&self, file: String) -> Option<&Sprite> {
        self.map.get(file.as_str())
    }
}

/// Struct for representing Necessary information about sprites
struct SpriteModel {
    image: &'static str,
    size_x: usize,
    size_y: usize,
    dur: usize,
    once: bool,
}

/// const with all Sprites
const SPRITES: &'static [SpriteModel] = &[SpriteModel {
                                              image: "bowman.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_brown.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_pink.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_white.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "explosion.png",
                                              size_x: 59,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "knight.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "paladin.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_broadsword.png",
                                              size_x: 64,
                                              size_y: 192,
                                              dur: 500,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 500,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_longsword.png",
                                              size_x: 128,
                                              size_y: 64,
                                              dur: 500,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "wizard.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_empty.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_full.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_half.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_10.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_20.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          }];
<commit_msg>change swipes speed<commit_after>// Module for reading sprides and saving them in a HashMap

use std::collections::HashMap;
use piston_window::*;
use io::sprite::Sprite;

/// HashMap for all given sprites
pub struct SpriteMap {
    pub map: HashMap<&'static str, Sprite>,
}

impl SpriteMap {
    /// Initialize the SpriteMap with given window, fills Map with all Sprites
    pub fn init(mut w: &mut PistonWindow) -> Self {
        let mut map2: HashMap<&'static str, Sprite> = HashMap::new();
        for i in SPRITES {
            map2.insert(i.image,
                        Sprite::fill_sprite(i.image, i.size_x as u32, i.size_y as u32,i.dur as u64, i.once, w));
        }

        SpriteMap { map: map2 }

    }

    /// creates empty SpriteMap
    pub fn new() -> Self {
        SpriteMap { map: HashMap::new() }
    }
    pub fn get_sprite(&self, file: String) -> Option<&Sprite> {
        self.map.get(file.as_str())
    }
}

/// Struct for representing Necessary information about sprites
struct SpriteModel {
    image: &'static str,
    size_x: usize,
    size_y: usize,
    dur: usize,
    once: bool,
}

/// const with all Sprites
const SPRITES: &'static [SpriteModel] = &[SpriteModel {
                                              image: "bowman.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_brown.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_pink.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "chicken_white.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "explosion.png",
                                              size_x: 59,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "knight.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "paladin.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "swipe_broadsword.png",
                                              size_x: 64,
                                              size_y: 192,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "swipe_longsword.png",
                                              size_x: 128,
                                              size_y: 64,
                                              dur: 100,
                                              once: true,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "wizard.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_empty.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_full.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_half.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_broadsword_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_dagger_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "weapon_spear_small.png",
                                              size_x: 32,
                                              size_y: 32,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_10.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          },
                                          SpriteModel {
                                              image: "Heart_20.png",
                                              size_x: 64,
                                              size_y: 64,
                                              dur: 1000,
                                              once: false,
                                          }];
<|endoftext|>


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

/*!

The `ToStr` trait for converting to strings

*/

use str;
use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;

pub trait ToStr {
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    // Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for bool {
    #[inline(always)]
    fn to_str(&self) -> ~str { ::bool::to_str(*self) }
}
impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                ~"(" + a.to_str() + ~", " + ~")"
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"{", first = true;
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
    let mut acc = ~"{", first = true;
    for self.each |element| {
        if first {
            first = false;
        }
        else {
            acc.push_str(", ");
        }
        acc.push_str(element.to_str());
    }
    acc.push_char('}');
    acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                ~"(" + a.to_str() + ~", " + b.to_str() + ~")"
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    #[test]
    fn test_simple_types() {
        assert!(1i.to_str() == ~"1");
        assert!((-1i).to_str() == ~"-1");
        assert!(200u.to_str() == ~"200");
        assert!(2u8.to_str() == ~"2");
        assert!(true.to_str() == ~"true");
        assert!(false.to_str() == ~"false");
        assert!(().to_str() == ~"()");
        assert!((~"hi").to_str() == ~"hi");
        assert!((@"hi").to_str() == ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert!((1, 2).to_str() == ~"(1, 2)");
        assert!((~"a", ~"b", false).to_str() == ~"(a, b, false)");
        assert!(((), ((), 100)).to_str() == ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert!(x.to_str() == ~"[]");
        assert!((~[1]).to_str() == ~"[1]");
        assert!((~[1, 2, 3]).to_str() == ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert!(empty.to_str() == ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int, int> = HashSet::new();
        let empty_set: HashSet<int, int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert!(empty.to_str() == ~"{}");
    }
}<commit_msg>Fix errors in test_hashset().<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `ToStr` trait for converting to strings

*/

use str;
use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;

pub trait ToStr {
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    // Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for bool {
    #[inline(always)]
    fn to_str(&self) -> ~str { ::bool::to_str(*self) }
}
impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                ~"(" + a.to_str() + ~", " + ~")"
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"{", first = true;
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
    let mut acc = ~"{", first = true;
    for self.each |element| {
        if first {
            first = false;
        }
        else {
            acc.push_str(", ");
        }
        acc.push_str(element.to_str());
    }
    acc.push_char('}');
    acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                ~"(" + a.to_str() + ~", " + b.to_str() + ~")"
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4760): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut acc = ~"[", first = true;
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    #[test]
    fn test_simple_types() {
        assert!(1i.to_str() == ~"1");
        assert!((-1i).to_str() == ~"-1");
        assert!(200u.to_str() == ~"200");
        assert!(2u8.to_str() == ~"2");
        assert!(true.to_str() == ~"true");
        assert!(false.to_str() == ~"false");
        assert!(().to_str() == ~"()");
        assert!((~"hi").to_str() == ~"hi");
        assert!((@"hi").to_str() == ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert!((1, 2).to_str() == ~"(1, 2)");
        assert!((~"a", ~"b", false).to_str() == ~"(a, b, false)");
        assert!(((), ((), 100)).to_str() == ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert!(x.to_str() == ~"[]");
        assert!((~[1]).to_str() == ~"[1]");
        assert!((~[1, 2, 3]).to_str() == ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert!(empty.to_str() == ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert!(empty_set.to_str() == ~"{}");
    }
}<|endoftext|>


<commit_before>extern crate moho;
extern crate sdl2_image;
extern crate sdl2;
extern crate glm;

use self::sdl2::event::Event;
use self::sdl2::keyboard::Keycode;
use self::sdl2::render::{Renderer, Texture};
use self::sdl2::rect;

use self::sdl2_image::{LoadTexture, INIT_PNG, INIT_JPG};
use std::error::Error;
use std::path::Path;

pub fn run() -> Result<(), Box<Error>> {
    const WINDOW_HEIGHT: u32 = 600;
    const WINDOW_WIDTH: u32 = 800;

    let (mut renderer, mut event_pump) =
        try!(moho::init("Master Smasher", WINDOW_WIDTH, WINDOW_HEIGHT));
    let _image_context = try!(sdl2_image::init(INIT_PNG | INIT_JPG));
    let mut input_manager = moho::input_manager::InputManager::new();
    let background_path = Path::new("resources/background_game.png");
    let meteor_path = Path::new("resources/meteor.png");

    let background = Background { texture: try!(renderer.load_texture(background_path)) };
    let mut meteor = Meteor::new(try!(renderer.load_texture(meteor_path)),
                                 glm::uvec2(WINDOW_WIDTH, WINDOW_HEIGHT));

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Some(key), .. } => {
                    input_manager.press_key(key);
                }
                Event::KeyUp { keycode: Some(key), .. } => {
                    input_manager.release_key(key);
                }
                _ => {}
            }
        }
        if input_manager.is_key_down(Keycode::Escape) {
            break;
        }
        meteor.update(&input_manager);

        renderer.clear();
        try!(background.draw(&mut renderer));
        try!(meteor.draw(&mut renderer));
        renderer.present();
    }

    Ok(())
}

struct Background {
    texture: Texture,
}

impl Background {
    fn draw(&self, renderer: &mut Renderer) -> Result<(), Box<Error>> {
        try!(renderer.copy(&self.texture, None, None));

        Ok(())
    }
}

struct Meteor {
    texture: Texture,
    rect: rect::Rect,
    max_coords: glm::Vector2<u32>,
}

impl Meteor {
    fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let rect = rect::Rect::new(0, 0, query.width, query.height);

        Meteor {
            texture: texture,
            rect: rect,
            max_coords: max_coords,
        }
    }

    fn update(&mut self, input_manager: &moho::input_manager::InputManager) {
        let mut top = self.rect.y();
        let mut left = self.rect.x();

        if input_manager.is_key_down(Keycode::Down) {
            top += 1;
        }

        if input_manager.is_key_down(Keycode::Up) {
            top -= 1;
        }

        if input_manager.is_key_down(Keycode::Left) {
            left -= 1;
        }

        if input_manager.is_key_down(Keycode::Right) {
            left += 1;
        }

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;

        self.rect.set_y((top + max_height) % max_height);
        self.rect.set_x((left + max_width) % max_width);
    }

    fn draw(&self, renderer: &mut Renderer) -> Result<(), Box<Error>> {
        try!(renderer.copy(&self.texture, None, Some(self.rect)));

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;

        if self.rect.bottom() > max_height {
            let mut wrapping_rect = self.rect.clone();
            let bottom = wrapping_rect.bottom() % max_height;
            wrapping_rect.set_bottom(bottom);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
        }

         if self.rect.right() > max_width {
            let mut wrapping_rect = self.rect.clone();
            let right = wrapping_rect.right() % max_width;
            wrapping_rect.set_right(right);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
         }

         if self.rect.bottom() > max_height && self.rect.right() > max_width {
            let mut wrapping_rect = self.rect.clone();
            let bottom = wrapping_rect.bottom() % max_height;
            let right = wrapping_rect.right() % max_width;
            wrapping_rect.set_bottom(bottom);
            wrapping_rect.set_right(right);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
        }

        Ok(())
    }
}
<commit_msg>refactored wrapping<commit_after>extern crate moho;
extern crate sdl2_image;
extern crate sdl2;
extern crate glm;

use self::sdl2::event::Event;
use self::sdl2::keyboard::Keycode;
use self::sdl2::render::{Renderer, Texture};
use self::sdl2::rect;

use self::sdl2_image::{LoadTexture, INIT_PNG, INIT_JPG};
use std::error::Error;
use std::path::Path;

pub fn run() -> Result<(), Box<Error>> {
    const WINDOW_HEIGHT: u32 = 600;
    const WINDOW_WIDTH: u32 = 800;

    let (mut renderer, mut event_pump) =
        try!(moho::init("Master Smasher", WINDOW_WIDTH, WINDOW_HEIGHT));
    let _image_context = try!(sdl2_image::init(INIT_PNG | INIT_JPG));
    let mut input_manager = moho::input_manager::InputManager::new();
    let background_path = Path::new("resources/background_game.png");
    let meteor_path = Path::new("resources/meteor.png");

    let background = Background { texture: try!(renderer.load_texture(background_path)) };
    let mut meteor = Meteor::new(try!(renderer.load_texture(meteor_path)),
                                 glm::uvec2(WINDOW_WIDTH, WINDOW_HEIGHT));

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Some(key), .. } => {
                    input_manager.press_key(key);
                }
                Event::KeyUp { keycode: Some(key), .. } => {
                    input_manager.release_key(key);
                }
                _ => {}
            }
        }
        if input_manager.is_key_down(Keycode::Escape) {
            break;
        }
        meteor.update(&input_manager);

        renderer.clear();
        try!(background.draw(&mut renderer));
        try!(meteor.draw(&mut renderer));
        renderer.present();
    }

    Ok(())
}

struct Background {
    texture: Texture,
}

impl Background {
    fn draw(&self, renderer: &mut Renderer) -> Result<(), Box<Error>> {
        try!(renderer.copy(&self.texture, None, None));

        Ok(())
    }
}

struct Meteor {
    texture: Texture,
    rect: rect::Rect,
    max_coords: glm::Vector2<u32>,
}

impl Meteor {
    fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let rect = rect::Rect::new(0, 0, query.width, query.height);

        Meteor {
            texture: texture,
            rect: rect,
            max_coords: max_coords,
        }
    }

    fn update(&mut self, input_manager: &moho::input_manager::InputManager) {
        let mut top = self.rect.y();
        let mut left = self.rect.x();

        if input_manager.is_key_down(Keycode::Down) {
            top += 1;
        }

        if input_manager.is_key_down(Keycode::Up) {
            top -= 1;
        }

        if input_manager.is_key_down(Keycode::Left) {
            left -= 1;
        }

        if input_manager.is_key_down(Keycode::Right) {
            left += 1;
        }

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;

        self.rect.set_y((top + max_height) % max_height);
        self.rect.set_x((left + max_width) % max_width);
    }

    fn draw(&self, renderer: &mut Renderer) -> Result<(), Box<Error>> {
        try!(renderer.copy(&self.texture, None, Some(self.rect)));

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;
        let bottom = self.rect.bottom();
        let right = self.rect.right();

        if bottom > max_height {
            let mut wrapping_rect = self.rect.clone();
            wrapping_rect.set_bottom(bottom % max_height);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
        }

        if right > max_width {
            let mut wrapping_rect = self.rect.clone();
            wrapping_rect.set_right(right % max_width);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
        }

        if bottom > max_height && right > max_width {
            let mut wrapping_rect = self.rect.clone();
            wrapping_rect.set_bottom(bottom % max_height);
            wrapping_rect.set_right(right % max_width);
            try!(renderer.copy(&self.texture, None, Some(wrapping_rect)));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use matching::fragment;
use matching::fragment::Fragment;
use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        let path_length = self.path.to_string_lossy().chars().count();

        let mut match_fragments: Vec<Fragment> = Vec::new();
        let mut non_existent_char_count = 0;

        for query_char in query.chars() {
            // Look for the query's character in the path's index, bumping
            // the character score up for each occurrence in the path.
            match self.index.get(&query_char) {
                Some(occurrences) => {
                    // Initially, we'll assume that none of the occurrences
                    // of this character have been tracked as fragments.
                    let mut unaccounted_occurrences = occurrences.clone();

                    // Grow any fragment matches that also match this char.
                    for fragment in match_fragments.iter_mut() {
                        let target_index = fragment.next_index();

                        if occurrences.contains(&target_index) {
                            // Since this character match is covered by this
                            // fragment, remove it from the unaccounted set.
                            match unaccounted_occurrences.iter().position(|&o| o == target_index) {
                                Some(position) => {
                                    unaccounted_occurrences.remove(position);
                                },
                                None => (),
                            }

                            // Bump the fragment's length to cover this char.
                            fragment.increase_length();
                        }
                    }

                    // Create fragment matches for any unaccounted occurrences.
                    for occurrence_index in unaccounted_occurrences.iter() {
                        match_fragments.push(fragment::new(*occurrence_index));
                    }

                },
                None => {
                    non_existent_char_count += 1;
                },
            }
        }

        let percent_existent = (
            path_length - non_existent_char_count) as f32 / path_length as f32;

        match_fragments.iter().fold(0, |acc, ref fragment| {
            acc + fragment.length.pow(2)
        }) as f32 * percent_existent / path_length as f32
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

#[cfg(test)]
mod tests {
    use super::new;

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("hound library".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity(" houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }
}
<commit_msg>Comments!<commit_after>use matching::fragment;
use matching::fragment::Fragment;
use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        // Pre-calculate the path length as we'll be using it frequently.
        let path_length = self.path.to_string_lossy().chars().count();

        // We track fragment/substring matches, which have a greater weight than
        // a simple sum of individual character occurrences in the entry path.
        let mut match_fragments: Vec<Fragment> = Vec::new();

        // This counter is used to track characters in the query that aren't in
        // the entry's path, which has discrete weighting in the final score.
        let mut non_existent_char_count = 0;

        // Look for the query's character in the path's index, bumping
        // the character score up for each occurrence in the path.
        for query_char in query.chars() {
            match self.index.get(&query_char) {
                Some(occurrences) => {
                    // Initially, we'll assume that none of the occurrences
                    // of this character have been tracked as fragments.
                    let mut unaccounted_occurrences = occurrences.clone();

                    // Extend any existing fragment matches that also
                    // have this char at the end of their existing match.
                    for fragment in match_fragments.iter_mut() {
                        // Get the index at which this character would have to
                        // occur to extend this particular fragment over it.
                        let target_index = fragment.next_index();

                        if occurrences.contains(&target_index) {
                            // Since this character match is covered by this
                            // fragment, remove it from the unaccounted set.
                            match unaccounted_occurrences.iter().position(|&o| o == target_index) {
                                Some(position) => {
                                    unaccounted_occurrences.remove(position);
                                },
                                None => (),
                            }

                            // Bump the fragment's length to cover this char.
                            fragment.increase_length();
                        }
                    }

                    // Create fragment matches for any unaccounted occurrences.
                    for occurrence_index in unaccounted_occurrences.iter() {
                        match_fragments.push(fragment::new(*occurrence_index));
                    }

                },
                None => {
                    // Characters in the query string that
                    // aren't in the path reduce the score;
                    // track these so we can consider them later.
                    non_existent_char_count += 1;
                },
            }
        }

        // Determine the percentage of characters in the query string that
        // are in the entry, using the non-existent count we've calculated.
        let non_existence_penalty = (
            path_length - non_existent_char_count) as f32 / path_length as f32;

        // Calculate an exponentially-scaled score based on fragment lengths.
        let fragment_score = match_fragments.iter().fold(0, |acc, ref fragment| {
            acc + fragment.length.pow(2)
        });

        // Calculate and return the similarity value. The path_length division
        // is used to offset the increased fragment score probability for
        // larger entry paths.
        fragment_score as f32 * non_existence_penalty / path_length as f32
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

#[cfg(test)]
mod tests {
    use super::new;

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("hound library".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity(" houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }
}
<|endoftext|>