<commit_before>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_room_id();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_monster_id()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
  }
}

fn random_room_id() -> RoomId {
  loop {
    let r = random_i32(0, NUM_ROOMS as i32);
    match RoomId::from_i32(r) {
      Some(room_id) => { return room_id; },
      None => {}
    }
  }
}

fn random_monster_id() -> MonsterId {
  loop {
    let r = random_i32(0, NUM_MONSTERS as i32);
    match MonsterId::from_i32(r) {
      Some(monster_id) => { return monster_id; },
      None => {}
    }
  }
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<commit_msg>Factor out random_enum().<commit_after>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_room_id();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_monster_id()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
  }
}

fn random_enum<T: FromPrimitive>(size: usize) -> T {
  loop {
    let r = random_i32(0, size as i32);
    match T::from_i32(r) {
      Some(t) => { return t; },
      None => {}
    }
  }
}

fn random_room_id() -> RoomId {
  random_enum(NUM_ROOMS)
}

fn random_monster_id() -> MonsterId {
  random_enum(NUM_MONSTERS)
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate byteorder;

use std::fs::File;
use std::io::Read;
use std::io::Cursor;
use std::mem;
use byteorder::{ByteOrder, LittleEndian, BigEndian, NativeEndian};
use std::iter::FromIterator;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> { Grid {points: Vec::new() } }

    // unformatted read from the buffer
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>);
}

struct Grid<T> {
    points: Vec<Vec<T>>,
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let real = if little_endian {
                    LittleEndian::read_f32(&grid_buf[start .. ])
                } else {
                    BigEndian::read_f32(&grid_buf[start .. ])
                };
                real
            }))
        }))
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) = if little_endian {
                    (LittleEndian::read_f32(&grid_buf[start_1 .. ]),
                     LittleEndian::read_f32(&grid_buf[start_2 .. ]))
                } else {
                    (BigEndian::read_f32(&grid_buf[start_1 .. ]),
                     BigEndian::read_f32(&grid_buf[start_2 .. ]))
                };
                c32::new(real, imag)
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let real = if little_endian {
                    LittleEndian::read_f64(&grid_buf[start .. ])
                } else {
                    BigEndian::read_f64(&grid_buf[start .. ])
                };
                real
            }))
        }));
    }
}

impl GridTrait<c64> for Grid<c64> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points =  Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f64>();
                let start_2 = start_1 + mem::size_of::<f64>(); // next f64 number
                let (real, imag) = if little_endian {
                    (LittleEndian::read_f64(&grid_buf[start_1 .. ]),
                     LittleEndian::read_f64(&grid_buf[start_2 .. ]))
                } else {
                    (BigEndian::read_f64(&grid_buf[start_1 .. ]),
                     BigEndian::read_f64(&grid_buf[start_2 .. ]))
                };
                c64::new(real, imag)
            }))
        }));
    }
}

fn main() {
    let mut grid = Grid::<f32>::new();
    grid.read(true, 8, 8, &vec![0u8; 64 * mem::size_of::<f32>()]);

    let mut grid1 = Grid::<c32>::new();
    grid1.read(true, 8, 8, &vec![0u8; 64 * mem::size_of::<c32>()]);
}

<commit_msg>added default `Grid::<T>::new()` that just `panic!`s.<commit_after>extern crate num;
extern crate byteorder;

use std::fs::File;
use std::io::Read;
use std::io::Cursor;
use std::mem;
use byteorder::{ByteOrder, LittleEndian, BigEndian, NativeEndian};
use std::iter::FromIterator;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> { Grid {points: Vec::new() } }

    // unformatted read from the buffer
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>);
}

struct Grid<T> {
    points: Vec<Vec<T>>,
}

impl <T> Grid<T> {
    fn new() -> Grid<T> { panic!("not implemented for generic type"); }
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let real = if little_endian {
                    LittleEndian::read_f32(&grid_buf[start .. ])
                } else {
                    BigEndian::read_f32(&grid_buf[start .. ])
                };
                real
            }))
        }))
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) = if little_endian {
                    (LittleEndian::read_f32(&grid_buf[start_1 .. ]),
                     LittleEndian::read_f32(&grid_buf[start_2 .. ]))
                } else {
                    (BigEndian::read_f32(&grid_buf[start_1 .. ]),
                     BigEndian::read_f32(&grid_buf[start_2 .. ]))
                };
                c32::new(real, imag)
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let real = if little_endian {
                    LittleEndian::read_f64(&grid_buf[start .. ])
                } else {
                    BigEndian::read_f64(&grid_buf[start .. ])
                };
                real
            }))
        }));
    }
}

impl GridTrait<c64> for Grid<c64> {
    fn read(&mut self,
            little_endian: bool,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points =  Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f64>();
                let start_2 = start_1 + mem::size_of::<f64>(); // next f64 number
                let (real, imag) = if little_endian {
                    (LittleEndian::read_f64(&grid_buf[start_1 .. ]),
                     LittleEndian::read_f64(&grid_buf[start_2 .. ]))
                } else {
                    (BigEndian::read_f64(&grid_buf[start_1 .. ]),
                     BigEndian::read_f64(&grid_buf[start_2 .. ]))
                };
                c64::new(real, imag)
            }))
        }));
    }
}

fn main() {
    let mut grid = Grid::<f32>::new();
    grid.read(true, 8, 8, &vec![0u8; 64 * mem::size_of::<f32>()]);

    let mut grid1 = Grid::<c32>::new();
    grid1.read(true, 8, 8, &vec![0u8; 64 * mem::size_of::<c32>()]);

    let mut grid2 = Grid::<i32>::new();
}

<|endoftext|>


<commit_before>use jansson_sys::json_t;
use std::os::raw::{c_char, c_int, c_void, c_short};

#[repr(C)]
#[derive(Debug)]
pub struct janus_callbacks {
    pub push_event: extern "C" fn(
        handle: *mut janus_plugin_session,
        plugin: *mut janus_plugin,
        transaction: *const c_char,
        message: *mut json_t,
        jsep: *mut json_t,
    ) -> c_int,
    pub relay_rtp: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtp),
    pub relay_rtcp: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtcp),
    pub relay_data: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_data),
    pub close_pc: extern "C" fn(handle: *mut janus_plugin_session),
    pub end_session: extern "C" fn(handle: *mut janus_plugin_session),
    pub events_is_enabled: extern "C" fn() -> c_int,
    pub notify_event: extern "C" fn(plugin: *mut janus_plugin, handle: *mut janus_plugin_session, event: *mut json_t),
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum janus_plugin_result_type {
    JANUS_PLUGIN_ERROR = -1,
    JANUS_PLUGIN_OK = 0,
    JANUS_PLUGIN_OK_WAIT = 1,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_session {
    pub gateway_handle: *mut c_void,
    pub plugin_handle: *mut c_void,
    pub stopped: c_int,
    pub ref_: crate::janus_refcount,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_result {
    pub type_: janus_plugin_result_type,
    pub text: *const c_char,
    pub content: *mut json_t,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtp_extensions {
    pub audio_level : c_char,
    pub audio_level_vad : c_char,
    pub video_rotation : c_short,
    pub video_back_camera : c_char,
    pub video_flipped : c_char,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtp {
    pub video :  c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
    pub extensions : janus_plugin_rtp_extensions,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtcp {
    pub video : c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_data {
    pub label : *mut c_char,
    pub binary : c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin {
    pub init: unsafe extern "C" fn(callback: *mut janus_callbacks, config_path: *const c_char) -> c_int,
    pub destroy: unsafe extern "C" fn(),
    pub get_api_compatibility: unsafe extern "C" fn() -> c_int,
    pub get_version: unsafe extern "C" fn() -> c_int,
    pub get_version_string: unsafe extern "C" fn() -> *const c_char,
    pub get_description: unsafe extern "C" fn() -> *const c_char,
    pub get_name: unsafe extern "C" fn() -> *const c_char,
    pub get_author: unsafe extern "C" fn() -> *const c_char,
    pub get_package: unsafe extern "C" fn() -> *const c_char,
    pub create_session: unsafe extern "C" fn(handle: *mut janus_plugin_session, error: *mut c_int),
    pub handle_message: unsafe extern "C" fn(
        handle: *mut janus_plugin_session,
        transaction: *mut c_char,
        message: *mut json_t,
        jsep: *mut json_t,
    ) -> *mut janus_plugin_result,
    pub handle_admin_message: unsafe extern "C" fn(message: *mut json_t) -> *mut json_t,
    pub setup_media: unsafe extern "C" fn(handle: *mut janus_plugin_session),
    pub incoming_rtp: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtp),
    pub incoming_rtcp: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtcp),
    pub incoming_data: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_data),
    pub slow_link: unsafe extern "C" fn(handle: *mut janus_plugin_session, uplink: c_int, video: c_int),
    pub hangup_media: unsafe extern "C" fn(handle: *mut janus_plugin_session),
    pub destroy_session: unsafe extern "C" fn(handle: *mut janus_plugin_session, error: *mut c_int),
    pub query_session: unsafe extern "C" fn(handle: *mut janus_plugin_session) -> *mut json_t,
}

extern "C" {
    pub fn janus_plugin_result_new(type_: janus_plugin_result_type, text: *const c_char, content: *mut json_t) -> *mut janus_plugin_result;
    pub fn janus_plugin_result_destroy(result: *mut janus_plugin_result);
}
<commit_msg>Add new send_pli and send_remb callback functions<commit_after>use jansson_sys::json_t;
use std::os::raw::{c_char, c_int, c_void, c_short};

#[repr(C)]
#[derive(Debug)]
pub struct janus_callbacks {
    pub push_event: extern "C" fn(
        handle: *mut janus_plugin_session,
        plugin: *mut janus_plugin,
        transaction: *const c_char,
        message: *mut json_t,
        jsep: *mut json_t,
    ) -> c_int,
    pub relay_rtp: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtp),
    pub relay_rtcp: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtcp),
    pub relay_data: extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_data),
    pub send_pli: extern "C" fn(handle: *mut janus_plugin_session),
    pub send_remb: extern "C" fn(handle: *mut janus_plugin_session, bitrate: c_int),
    pub close_pc: extern "C" fn(handle: *mut janus_plugin_session),
    pub end_session: extern "C" fn(handle: *mut janus_plugin_session),
    pub events_is_enabled: extern "C" fn() -> c_int,
    pub notify_event: extern "C" fn(plugin: *mut janus_plugin, handle: *mut janus_plugin_session, event: *mut json_t),
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum janus_plugin_result_type {
    JANUS_PLUGIN_ERROR = -1,
    JANUS_PLUGIN_OK = 0,
    JANUS_PLUGIN_OK_WAIT = 1,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_session {
    pub gateway_handle: *mut c_void,
    pub plugin_handle: *mut c_void,
    pub stopped: c_int,
    pub ref_: crate::janus_refcount,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_result {
    pub type_: janus_plugin_result_type,
    pub text: *const c_char,
    pub content: *mut json_t,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtp_extensions {
    pub audio_level : c_char,
    pub audio_level_vad : c_char,
    pub video_rotation : c_short,
    pub video_back_camera : c_char,
    pub video_flipped : c_char,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtp {
    pub video :  c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
    pub extensions : janus_plugin_rtp_extensions,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_rtcp {
    pub video : c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin_data {
    pub label : *mut c_char,
    pub binary : c_char,
    pub buffer : *mut c_char,
    pub length : c_short,
}

#[repr(C)]
#[derive(Debug)]
pub struct janus_plugin {
    pub init: unsafe extern "C" fn(callback: *mut janus_callbacks, config_path: *const c_char) -> c_int,
    pub destroy: unsafe extern "C" fn(),
    pub get_api_compatibility: unsafe extern "C" fn() -> c_int,
    pub get_version: unsafe extern "C" fn() -> c_int,
    pub get_version_string: unsafe extern "C" fn() -> *const c_char,
    pub get_description: unsafe extern "C" fn() -> *const c_char,
    pub get_name: unsafe extern "C" fn() -> *const c_char,
    pub get_author: unsafe extern "C" fn() -> *const c_char,
    pub get_package: unsafe extern "C" fn() -> *const c_char,
    pub create_session: unsafe extern "C" fn(handle: *mut janus_plugin_session, error: *mut c_int),
    pub handle_message: unsafe extern "C" fn(
        handle: *mut janus_plugin_session,
        transaction: *mut c_char,
        message: *mut json_t,
        jsep: *mut json_t,
    ) -> *mut janus_plugin_result,
    pub handle_admin_message: unsafe extern "C" fn(message: *mut json_t) -> *mut json_t,
    pub setup_media: unsafe extern "C" fn(handle: *mut janus_plugin_session),
    pub incoming_rtp: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtp),
    pub incoming_rtcp: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_rtcp),
    pub incoming_data: unsafe extern "C" fn(handle: *mut janus_plugin_session, packet: *mut janus_plugin_data),
    pub slow_link: unsafe extern "C" fn(handle: *mut janus_plugin_session, uplink: c_int, video: c_int),
    pub hangup_media: unsafe extern "C" fn(handle: *mut janus_plugin_session),
    pub destroy_session: unsafe extern "C" fn(handle: *mut janus_plugin_session, error: *mut c_int),
    pub query_session: unsafe extern "C" fn(handle: *mut janus_plugin_session) -> *mut json_t,
}

extern "C" {
    pub fn janus_plugin_result_new(type_: janus_plugin_result_type, text: *const c_char, content: *mut json_t) -> *mut janus_plugin_result;
    pub fn janus_plugin_result_destroy(result: *mut janus_plugin_result);
}
<|endoftext|>


<commit_before>
use std::{ptr};
use std::mem::{transmute};
pub struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(windows)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        unsafe {
            let mut name = path.as_str().unwrap().to_utf16();
            name.push(0);
            let handle =
                CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(unix)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::posix88::fcntl::open;
        use libc::funcs::posix88::stat_::fstat;
        use libc::funcs::posix88::mman::mmap;
        use libc::consts::os::posix88::{O_RDONLY, PROT_READ, MAP_SHARED};
        use libc::types::os::arch::posix01::stat;
        use std::mem::uninitialized;
        unsafe {
            let name = path.to_c_str();
            let handle = open(name.unwrap(), O_RDONLY, 0);
            if (handle == -1) { return None; }
            let mut finfo = uninitialized::<stat>();
            if (fstat(handle, &mut finfo) == -1) { return None; }
            let size = finfo.st_size;
            let data =
                mmap(ptr::null(), size as u64, PROT_READ, MAP_SHARED, handle,
                     0);
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    fn get_header(&self) -> &Header { unsafe { transmute(self.header) } }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf); str::from_utf8(bytes) };
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> {
        self.file.get_str(self.data.name)
    }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<commit_msg>Get rid of global uses.<commit_after>pub struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(windows)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        use std::ptr;
        use std::mem::transmute;
        unsafe {
            let mut name = path.as_str().unwrap().to_utf16();
            name.push(0);
            let handle =
                CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(unix)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::posix88::fcntl::open;
        use libc::funcs::posix88::stat_::fstat;
        use libc::funcs::posix88::mman::mmap;
        use libc::consts::os::posix88::{O_RDONLY, PROT_READ, MAP_SHARED};
        use libc::types::os::arch::posix01::stat;
        use std::mem::{uninitialized, transmute};
        use std::ptr;
        unsafe {
            let name = path.to_c_str();
            let handle = open(name.unwrap(), O_RDONLY, 0);
            if (handle == -1) { return None; }
            let mut finfo = uninitialized::<stat>();
            if (fstat(handle, &mut finfo) == -1) { return None; }
            let size = finfo.st_size;
            let data =
                mmap(ptr::null(), size as u64, PROT_READ, MAP_SHARED, handle,
                     0);
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    fn get_header(&self) -> &Header {
        use std::mem::transmute;
        unsafe { transmute(self.header) }
    }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        use std::ptr;
        use std::mem::transmute;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf); str::from_utf8(bytes) };
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> {
        self.file.get_str(self.data.name)
    }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<|endoftext|>


<commit_before>use super::web::{self, sqlite::create_connection_pool};
use crate::core::prelude::*;
use crate::infrastructure::osm;
use clap::{App, Arg, SubCommand};
use dotenv::dotenv;
use std::{env, process};

const DEFAULT_DB_URL: &str = "openfair.db";

fn update_event_locations<D: Db>(db: &mut D) -> Result<()> {
    let events = db.all_events()?;
    for mut e in events {
        if let Some(ref mut loc) = e.location {
            if let Some(ref addr) = loc.address {
                if let Some((lat, lng)) = web::api::geocoding::resolve_address_lat_lng(addr) {
                    loc.lat = lat;
                    loc.lng = lng;
                    if let Err(err) = db.update_event(&e) {
                        warn!("Failed to update location of event {}: {}", e.id, err);
                    } else {
                        info!("Updated location of event {}", e.id);
                    }
                }
            }
        }
    }
    Ok(())
}

pub fn run() {
    dotenv().ok();
    let matches = App::new("openFairDB")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Kohlhase <mail@markus-kohlhase.de>")
        .arg(
            Arg::with_name("db-url")
                .long("db-url")
                .value_name("DATABASE_URL")
                .help("URL to the database"),
        )
        .arg(
            Arg::with_name("enable-cors")
                .long("enable-cors")
                .help("Allow requests from any origin"),
        )
        .arg(
            Arg::with_name("fix-event-address-location")
                .long("fix-event-address-location")
                .help("Update the location of ALL events by resolving their address"),
        )
        .subcommand(
            SubCommand::with_name("osm")
                .about("OpenStreetMap functionalities")
                .subcommand(
                    SubCommand::with_name("import")
                        .about("import entries from OSM (JSON file)")
                        .arg(
                            Arg::with_name("osm-file")
                                .value_name("OSM_FILE")
                                .help("JSON file with osm nodes"),
                        ),
                ),
        )
        .get_matches();

    let db_url = match matches.value_of("db-url") {
        Some(db_url) => db_url.into(),
        None => match env::var("DATABASE_URL") {
            Ok(url) => url,
            Err(_) => DEFAULT_DB_URL.to_string(),
        },
    };
    let pool = create_connection_pool(&db_url).unwrap();

    match matches.subcommand() {
        ("osm", Some(osm_matches)) => match osm_matches.subcommand() {
            ("import", Some(import_matches)) => {
                let osm_file = match import_matches.value_of("osm-file") {
                    Some(osm_file) => osm_file,
                    None => {
                        println!("{}", matches.usage());
                        process::exit(1)
                    }
                };
                if let Err(err) = osm::import_from_osm_file(&db_url, osm_file) {
                    println!("Could not import from '{}': {}", osm_file, err);
                    process::exit(1)
                }
            }
            _ => println!("{}", osm_matches.usage()),
        },
        _ => {
            if matches.is_present("fix-event-address-location") {
                info!("Updating all event locations...");
                update_event_locations(&mut *pool.get().unwrap()).unwrap();
            }
            web::run(pool, matches.is_present("enable-cors"));
        }
    }
}
<commit_msg>Reset location for events with an empty address<commit_after>use super::web::{self, sqlite::create_connection_pool};
use crate::core::prelude::*;
use crate::infrastructure::osm;
use clap::{App, Arg, SubCommand};
use dotenv::dotenv;
use std::{env, process};

const DEFAULT_DB_URL: &str = "openfair.db";

fn update_event_locations<D: Db>(db: &mut D) -> Result<()> {
    let events = db.all_events()?;
    for mut e in events {
        if let Some(ref mut loc) = e.location {
            if let Some(ref addr) = loc.address {
                if let Some((lat, lng)) = web::api::geocoding::resolve_address_lat_lng(addr) {
                    loc.lat = lat;
                    loc.lng = lng;
                } else {
                    // Reset existing location if an address exists but is
                    // empty. This compensates for a bug in v0.4.3 where the
                    // check for an empty address was missing.
                    if addr.is_empty() {
                        info!("Resetting location of event {} with empty address: {}", e.id, err);
                        loc.lat = 0.0;
                        loc.lng = 0.0;
                    }
                }
                if let Err(err) = db.update_event(&e) {
                    warn!("Failed to update location of event {}: {}", e.id, err);
                } else {
                    info!("Updated location of event {}", e.id);
                }
            }
        }
    }
    Ok(())
}

pub fn run() {
    dotenv().ok();
    let matches = App::new("openFairDB")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Kohlhase <mail@markus-kohlhase.de>")
        .arg(
            Arg::with_name("db-url")
                .long("db-url")
                .value_name("DATABASE_URL")
                .help("URL to the database"),
        )
        .arg(
            Arg::with_name("enable-cors")
                .long("enable-cors")
                .help("Allow requests from any origin"),
        )
        .arg(
            Arg::with_name("fix-event-address-location")
                .long("fix-event-address-location")
                .help("Update the location of ALL events by resolving their address"),
        )
        .subcommand(
            SubCommand::with_name("osm")
                .about("OpenStreetMap functionalities")
                .subcommand(
                    SubCommand::with_name("import")
                        .about("import entries from OSM (JSON file)")
                        .arg(
                            Arg::with_name("osm-file")
                                .value_name("OSM_FILE")
                                .help("JSON file with osm nodes"),
                        ),
                ),
        )
        .get_matches();

    let db_url = match matches.value_of("db-url") {
        Some(db_url) => db_url.into(),
        None => match env::var("DATABASE_URL") {
            Ok(url) => url,
            Err(_) => DEFAULT_DB_URL.to_string(),
        },
    };
    let pool = create_connection_pool(&db_url).unwrap();

    match matches.subcommand() {
        ("osm", Some(osm_matches)) => match osm_matches.subcommand() {
            ("import", Some(import_matches)) => {
                let osm_file = match import_matches.value_of("osm-file") {
                    Some(osm_file) => osm_file,
                    None => {
                        println!("{}", matches.usage());
                        process::exit(1)
                    }
                };
                if let Err(err) = osm::import_from_osm_file(&db_url, osm_file) {
                    println!("Could not import from '{}': {}", osm_file, err);
                    process::exit(1)
                }
            }
            _ => println!("{}", osm_matches.usage()),
        },
        _ => {
            if matches.is_present("fix-event-address-location") {
                info!("Updating all event locations...");
                update_event_locations(&mut *pool.get().unwrap()).unwrap();
            }
            web::run(pool, matches.is_present("enable-cors"));
        }
    }
}
<|endoftext|>


<commit_before>use std::uint;

/// Generate an iterator like [0, 1, -1, 2, -2, n, -n].
pub struct RangeAbs {
  n: int,
  max: int,
}

pub fn range_abs(inclusive_max: int) -> RangeAbs {
  RangeAbs {
    n: 0,
    max: inclusive_max,
  }
}

impl Iterator<int> for RangeAbs {
  fn next(&mut self) -> Option<int> {
    if self.n == 0 {
      self.n = 1;
      Some(0)
    } else {
      let r = self.n;
      if r > 0 {
        if r == self.max + 1 {
          None
        } else {
          self.n = -self.n;
          Some(r)
        }
      } else {
        self.n = -self.n + 1;
        Some(r)
      }
    }
  }

  fn size_hint(&self) -> (uint, Option<uint>) {
    (uint::MAX, None)
  }
}

#[test]
pub fn basic_test() {
  let mut range = range_abs(2);
  assert_eq!(range.next(), Some(0));
  assert_eq!(range.next(), Some(1));
  assert_eq!(range.next(), Some(-1));
  assert_eq!(range.next(), Some(2));
  assert_eq!(range.next(), Some(-2));
  assert_eq!(range.next(), None);
}
<commit_msg>check that range_abs's parameter is nonnegative<commit_after>use std::uint;

/// Generate an iterator like [0, 1, -1, 2, -2, n, -n].
pub struct RangeAbs {
  n: int,
  max: int,
}

pub fn range_abs(inclusive_max: int) -> RangeAbs {
  assert!(inclusive_max >= 0);
  RangeAbs {
    n: 0,
    max: inclusive_max,
  }
}

impl Iterator<int> for RangeAbs {
  fn next(&mut self) -> Option<int> {
    if self.n == 0 {
      self.n = 1;
      Some(0)
    } else {
      let r = self.n;
      if r > 0 {
        if r == self.max + 1 {
          None
        } else {
          self.n = -self.n;
          Some(r)
        }
      } else {
        self.n = -self.n + 1;
        Some(r)
      }
    }
  }

  fn size_hint(&self) -> (uint, Option<uint>) {
    (uint::MAX, None)
  }
}

#[test]
fn basic_test() {
  let mut range = range_abs(2);
  assert_eq!(range.next(), Some(0));
  assert_eq!(range.next(), Some(1));
  assert_eq!(range.next(), Some(-1));
  assert_eq!(range.next(), Some(2));
  assert_eq!(range.next(), Some(-2));
  assert_eq!(range.next(), None);
}

#[test]
fn test_range_abs_0() {
  let mut range = range_abs(0);
  assert_eq!(range.next(), Some(0));
  assert_eq!(range.next(), None);
}
<|endoftext|>


<commit_before>use std::iter::Iterator;
use std::result;
use std::collections::HashSet;

use token::Token;
use scanner::Scanner;

const EOL_CHAR: char = '\n';

lazy_static! {
    static ref SYMBOL_CHARS: HashSet<char> = vec![
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
        'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '-', '_', '$', '^', '&', '*', '!', '@', '%', '+',
        '?', '<', '>', '.', ':', '/', '|', '~', ',', '='
    ].into_iter().collect();
}

#[derive(Debug, Eq, PartialEq)]
pub enum TokenError {
    UnrecognizedCharacter(char),
    UnexpectedEndOfInput,
    SymbolCannotBeNumber,
    ScannerError(String),
}

pub type TokenResult = result::Result<Token, TokenError>;

pub struct Tokenizer {
    scanner: Scanner,
    reached_eof: bool,
}

impl Tokenizer {
    pub fn new(scanner: Scanner) -> Tokenizer {
        Tokenizer {
            scanner: scanner,
            reached_eof: false,
        }
    }

    fn ignore_whitespace(&mut self) -> result::Result<(), &str> {
        loop {
            let c = self.scanner.get_char();
            if c.is_none() {
                break;
            }

            let c = c.unwrap();
            if !c.is_whitespace() || c == EOL_CHAR {
                try!(self.scanner.unget_char());
                break;
            }
        }

        Ok(())
    }

    fn next_symbol(&mut self, start: char) -> Option<TokenResult> {
        let mut symbol = String::new();

        let mut next_char = Some(start);
        while !next_char.is_none() {
            let c = next_char.unwrap();
            if SYMBOL_CHARS.contains(&c) {
                symbol.push(c)
            }
            else {
                if let Err(message) = self.scanner.unget_char() {
                    return Some(Err(TokenError::ScannerError(message.to_owned())));
                }
                break;
            }

            next_char = self.scanner.get_char();
        }

        if symbol.len() == 0 {
            Some(Err(match self.scanner.get_char() {
                Some(c) => TokenError::UnrecognizedCharacter(c),
                None => TokenError::UnexpectedEndOfInput,
            }))
        }
        else if symbol.chars().next().map_or(false, |c| c.is_digit(10)) {
            Some(Err(TokenError::SymbolCannotBeNumber))
        }
        else if symbol == "=" {
            Some(Ok(Token::Equals))
        }
        else {
            Some(Ok(Token::Symbol(symbol)))
        }
    }
}

impl Iterator for Tokenizer {
    type Item = TokenResult;

    fn next(&mut self) -> Option<Self::Item> {
        if self.reached_eof {
            return None;
        }

        if let Err(message) = self.ignore_whitespace() {
            return Some(Err(TokenError::ScannerError(message.to_owned())));
        }

        let c = self.scanner.get_char();
        if c.is_none() {
            self.reached_eof = true;
            return None;
        }

        let c = c.unwrap();
        Some(Ok(match c {
            '\\' => Token::Backslash,
            '(' => Token::ParenOpen,
            ')' => Token::ParenClose,
            '"' => Token::StringBoundary,
            EOL_CHAR => Token::EOL,
            _ => {
                if let Some(symbol_result) = self.next_symbol(c) {
                    return Some(symbol_result);
                }
                else {
                    return None;
                }
            },
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token::*;
    use scanner::Scanner;

    #[test]
    fn backslash() {
        let mut tokenizer = tokenizer_for("\\");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Backslash);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn equals() {
        let mut tokenizer = tokenizer_for("=");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Equals);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_open() {
        let mut tokenizer = tokenizer_for("(");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenOpen);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_close() {
        let mut tokenizer = tokenizer_for(")");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenClose);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn string_boundary() {
        let mut tokenizer = tokenizer_for("\"");
        assert_eq!(tokenizer.next().unwrap().unwrap(), StringBoundary);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn eol() {
        let mut tokenizer = tokenizer_for("\n");
        assert_eq!(tokenizer.next().unwrap().unwrap(), EOL);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_multiple_tokens_separated_by_whitespace() {
        let mut tokenizer = tokenizer_for("\\ ) \n ( \\ = = )");
        let expected = [Backslash, ParenClose, EOL, ParenOpen, Backslash, Equals, Equals, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_characters_into_symbols() {
        let symbol = "abqq$$1111^&/|!";
        let mut tokenizer = tokenizer_for(symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_equals_into_symbols_when_there_is_no_whitespace() {
        let symbol = "=ifsaoi=hfsdMMDS,,,,~~~:=".to_owned();

        // Make sure leading whitespace does not effect the output
        let mut tokenizer = tokenizer_for(&format!("  {}", symbol));

        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_symbols_starting_with_numbers() {
        let symbol = "123abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::SymbolCannotBeNumber);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_invalid_characters() {
        let symbol = "]";
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter(']'));
        assert!(tokenizer.next().is_none());

        // Make sure invalid character is caught among valid characters too
        let symbol = "a12[3abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);

        // Ignore first token
        assert!(tokenizer.next().unwrap().is_ok());
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter('['));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn accepts_all_valid_symbol_characters_into_a_symbol() {
        let symbol = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_$^&*!@%+?<>.:/|~,=".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_parenthesis_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("(x + y)())");
        let expected = [ParenOpen, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), ParenClose, ParenOpen, ParenClose, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_string_boundaries_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("\"x + y\"\"\"\"");
        let expected = [StringBoundary, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), StringBoundary, StringBoundary, StringBoundary, StringBoundary];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn ignores_leading_whitespace() {
        let symbol = "oh#*$ho".to_owned();
        let mut tokenizer = tokenizer_for(&format!("  \t\t  \t {}", symbol));
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    fn tokenizer_for(string: &str) -> Tokenizer {
        Tokenizer::new(Scanner::from_str(string))
    }
}

<commit_msg>Fixing tests so everything passes<commit_after>use std::iter::Iterator;
use std::result;
use std::collections::HashSet;

use token::Token;
use scanner::Scanner;

const EOL_CHAR: char = '\n';

lazy_static! {
    static ref SYMBOL_CHARS: HashSet<char> = vec![
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
        'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '-', '_', '$', '^', '&', '*', '!', '@', '%', '+',
        '?', '<', '>', '.', ':', '/', '|', '~', ',', '='
    ].into_iter().collect();
}

#[derive(Debug, Eq, PartialEq)]
pub enum TokenError {
    UnrecognizedCharacter(char),
    UnexpectedEndOfInput,
    SymbolCannotBeNumber,
    ScannerError(String),
}

pub type TokenResult = result::Result<Token, TokenError>;

pub struct Tokenizer {
    scanner: Scanner,
    reached_eof: bool,
}

impl Tokenizer {
    pub fn new(scanner: Scanner) -> Tokenizer {
        Tokenizer {
            scanner: scanner,
            reached_eof: false,
        }
    }

    fn ignore_whitespace(&mut self) -> result::Result<(), &str> {
        loop {
            let c = self.scanner.get_char();
            if c.is_none() {
                break;
            }

            let c = c.unwrap();
            if !c.is_whitespace() || c == EOL_CHAR {
                try!(self.scanner.unget_char());
                break;
            }
        }

        Ok(())
    }

    fn next_symbol(&mut self, start: char) -> Option<TokenResult> {
        let mut symbol = String::new();

        let mut next_char = Some(start);
        while !next_char.is_none() {
            let c = next_char.unwrap();
            if SYMBOL_CHARS.contains(&c) {
                symbol.push(c)
            }
            else {
                if let Err(message) = self.scanner.unget_char() {
                    return Some(Err(TokenError::ScannerError(message.to_owned())));
                }
                break;
            }

            next_char = self.scanner.get_char();
        }

        if symbol.len() == 0 {
            Some(Err(match self.scanner.get_char() {
                Some(c) => TokenError::UnrecognizedCharacter(c),
                None => TokenError::UnexpectedEndOfInput,
            }))
        }
        else if symbol.chars().next().map_or(false, |c| c.is_digit(10)) {
            Some(Err(TokenError::SymbolCannotBeNumber))
        }
        else if symbol == "=" {
            Some(Ok(Token::Equals))
        }
        else {
            Some(Ok(Token::Symbol(symbol)))
        }
    }
}

impl Iterator for Tokenizer {
    type Item = TokenResult;

    fn next(&mut self) -> Option<Self::Item> {
        if self.reached_eof {
            return None;
        }

        if let Err(message) = self.ignore_whitespace() {
            return Some(Err(TokenError::ScannerError(message.to_owned())));
        }

        let c = self.scanner.get_char();
        if c.is_none() {
            self.reached_eof = true;
            return None;
        }

        let c = c.unwrap();
        Some(Ok(match c {
            '\\' => Token::Backslash,
            '(' => Token::ParenOpen,
            ')' => Token::ParenClose,
            '"' => Token::StringBoundary,
            EOL_CHAR => Token::EOL,
            _ => {
                if let Some(symbol_result) = self.next_symbol(c) {
                    return Some(symbol_result);
                }
                else {
                    return None;
                }
            },
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token::*;
    use scanner::Scanner;

    #[test]
    fn backslash() {
        let mut tokenizer = tokenizer_for("\\");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Backslash);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn equals() {
        let mut tokenizer = tokenizer_for("=");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Equals);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_open() {
        let mut tokenizer = tokenizer_for("(");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenOpen);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_close() {
        let mut tokenizer = tokenizer_for(")");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenClose);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn string_boundary() {
        let mut tokenizer = tokenizer_for("\"");
        assert_eq!(tokenizer.next().unwrap().unwrap(), StringBoundary);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn eol() {
        let mut tokenizer = tokenizer_for("\n");
        assert_eq!(tokenizer.next().unwrap().unwrap(), EOL);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_multiple_tokens_separated_by_whitespace() {
        let mut tokenizer = tokenizer_for("\\ ) \n ( \\ = = )");
        let expected = [Backslash, ParenClose, EOL, ParenOpen, Backslash, Equals, Equals, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_characters_into_symbols() {
        let symbol = "abqq$$1111^&/|!";
        let mut tokenizer = tokenizer_for(symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_equals_into_symbols_when_there_is_no_whitespace() {
        let symbol = "=ifsaoi=hfsdMMDS,,,,~~~:=".to_owned();

        // Make sure leading whitespace does not effect the output
        let mut tokenizer = tokenizer_for(&format!("  {}", symbol));

        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_symbols_starting_with_numbers() {
        let symbol = "123abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::SymbolCannotBeNumber);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_invalid_characters() {
        let symbol = "]";
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter(']'));
        assert!(tokenizer.next().is_none());

        // Make sure invalid character is caught among valid characters too
        let symbol = "a12[$3abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);

        // Ignore first token
        assert!(tokenizer.next().unwrap().is_ok());
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter('['));
        assert!(tokenizer.next().unwrap().is_ok());
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn accepts_all_valid_symbol_characters_into_a_symbol() {
        let symbol = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_$^&*!@%+?<>.:/|~,=".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_parenthesis_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("(x + y)())");
        let expected = [ParenOpen, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), ParenClose, ParenOpen, ParenClose, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_string_boundaries_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("\"x + y\"\"\"\"");
        let expected = [StringBoundary, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), StringBoundary, StringBoundary, StringBoundary, StringBoundary];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn ignores_leading_whitespace() {
        let symbol = "oh$*$ho".to_owned();
        let mut tokenizer = tokenizer_for(&format!("  \t\t  \t {}", symbol));
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    fn tokenizer_for(string: &str) -> Tokenizer {
        Tokenizer::new(Scanner::from_str(string))
    }
}

<|endoftext|>


<commit_before>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if c.is_numeric() => {
                let x: f64 = from_str(c.to_string().as_slice()).unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.finish_word().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn finish_word(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.finish_word().as_slice(),
        }
    }

    /*
    fn finish_number(&mut self) -> String {
    }
    */
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<commit_msg>Better number tokenizing, and tests!<commit_after>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-'           => true,
        _                   => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let number = c.to_string() + self.read_until_whitespace().as_slice();
                let x: f64 = from_str(number.as_slice()).unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }

    /*
    fn finish_number(&mut self) -> String {
    }
    */
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello".to_string()),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world".to_string()),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "4.2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".38 -2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "0.38"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<|endoftext|>


<commit_before>/*!
Simple player bot.
*/

use ::std::f64;

use ::{Well, Rot, Piece, Player, Point, State, MAX_WIDTH, MAX_HEIGHT};

/// Weights for evaluating well.
pub struct Weights {
	/// Factor for the total combined height of all the columns.
	pub agg_height_f: f64,
	/// Factor for the number of completed lines.
	pub complete_lines_f: f64,
	/// Factor for the number of holes in the field.
	pub holes_f: f64,
	/// Factor for the sum of the absolute differences between two adjacent columns.
	pub bumpiness_f: f64,
	/// Factor for the number blocks above a hole.
	pub stacking_f: f64,
}

impl Weights {
	/// Returns some nice weights.
	///
	/// Gently appropriated from https://codemyroad.wordpress.com/2013/04/14/tetris-ai-the-near-perfect-player/
	pub fn new() -> Weights {
		Weights {
			agg_height_f: -0.510066,
			complete_lines_f: 0.760666,
			holes_f: -0.35663,
			bumpiness_f: -0.184483,
			stacking_f: -0.5,

			// heights: -0.03,
			// lines: 8.0,
			// holes: -7.5,
			// bumpiness: -3.5,
			// walltouch: 6.52,

			// heights: -3.78,
			// lines: 1.6,
			// holes: -2.31,
			// bumpiness: -0.184483,
			// walltouch: 6.52,
		}
	}
	/// Evaluates a well and returns a score.
	///
	/// The score is the sum of result of each category multiplied by the appropriated multiplier.
	///
	/// This value only has meaning in comparison to other wells.
	/// A higher value indicates a better scoring well.
	pub fn eval(&self, well: &Well) -> f64 {
		let (agg_height, completed_lines, holes, bumpiness, stacks) = Self::crunch(well);
		return
			self.agg_height_f * agg_height as f64 +
			self.complete_lines_f * completed_lines as f64 +
			self.holes_f * holes as f64 +
			self.bumpiness_f * bumpiness as f64 +
			self.stacking_f * stacks as f64;
	}
	fn crunch(well: &Well) -> (i32, i32, i32, i32, i32) {
		let width = well.width() as usize;
		let mut heights = [0i32; MAX_WIDTH];
		let mut holes = [0i32; MAX_WIDTH];
		let mut stacks = [0i32; MAX_WIDTH];
		let _ = heights[..width];
		let _ = holes[..width];
		let _ = stacks[..width];
		let mut lines = 0;
		let line_mask = well.line_mask();

		let mut height = 0;
		for &line in well.lines() {
			// Skip cleared lines
			if line == line_mask {
				lines += 1;
			}
			else {
				height += 1;
				let mut line = line;
				for col in 0..width {
					if line & 1 != 0 {
						// Sum the holes for this column
						holes[col] += height - heights[col] - 1;
						// Save the height for this column
						heights[col] = height;
						// Save the stacks for this column
						stacks[col] += (holes[col] != 0) as i32;
					}
					line >>= 1;
				}
			}
		}

		let height_sum = heights[..width].iter().sum();
		let holes_sum = holes[..width].iter().sum();
		let stacks_sum = stacks[..width].iter().sum();
		let bumpiness = heights[..width].windows(2).map(|window| (window[0] - window[1]).abs()).sum();

		(height_sum, lines, holes_sum, bumpiness, stacks_sum)
	}
}

/// Player move.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum Play {
	Idle,
	MoveLeft,
	MoveRight,
	RotateCW,
	RotateCCW,
	SoftDrop,
	HardDrop,
}

/// Player AI.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PlayI {
	x: i8,
	rot: Rot,
	score: f64,
}

impl PlayI {
	/// Brute force the best move with the given well and weights.
	pub fn best(weights: &Weights, well: &Well, piece: Piece) -> PlayI {
		// Brute force a solution...
		let mut best_x = 0;
		let mut best_rot = Rot::Zero;
		let mut best_score = f64::NEG_INFINITY;
		for rot in 0..3 {
			for x in -3..well.width() {
				let rot = Rot::from(rot);
				let mut player = Player::new(piece, rot, Point::new(x, well.height()));
				// Early reject against the walls
				if well.test(&player) {
					continue;
				}
				// Drop the piece down
				while !well.test(&player) {
					player.pt.y -= 1;
				}
				player.pt.y += 1;
				// Evaluate the well
				let mut well = well.clone();
				well.etch(&player);
				let score = weights.eval(&well);
				// Keep the best scoring move
				if score > best_score {
					best_x = x;
					best_rot = rot;
					best_score = score;
				}
			}
		}
		PlayI {
			x: best_x,
			rot: best_rot,
			score: best_score,
		}
	}
	/// Brute force the worst piece for the given well and weights.
	pub fn worst_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::S, Piece::Z, Piece::O, Piece::I, Piece::L, Piece::J, Piece::T];
		pieces[..].iter().fold((pieces[0], f64::INFINITY), |(bad_piece, bad_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score < bad_score {
				(piece, score)
			}
			else {
				(bad_piece, bad_score)
			}
		}).0
	}
	/// Brute force the best piece for the given well and weights.
	pub fn best_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::T, Piece::J, Piece::L, Piece::I, Piece::O, Piece::Z, Piece::S];
		pieces[..].iter().fold((pieces[0], f64::NEG_INFINITY), |(good_piece, good_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score > good_score {
				(piece, score)
			}
			else {
				(good_piece, good_score)
			}
		}).0
	}
	fn path(weights: &Weights, well: &Well, player: Player) -> (f64, Vec<Play>) {
		const STRIDE: usize = (MAX_WIDTH + 3) * 4;
		const SIZE: usize = STRIDE * (MAX_HEIGHT + 4);
		type Visited = [bool; SIZE];
		let mut visited = [false; SIZE];
		let mut path: Vec<(Play, Player)> = Vec::new();
		path.push((Play::SoftDrop, player));
		let mut best_score = f64::NEG_INFINITY;
		let mut best_play = Vec::new();
		// Depth first floodfill
		while let Some((play, player)) = path.last().cloned() {
			match play {
				Play::Idle => {
					path.pop();
				},
				Play::SoftDrop => {
					path.last_mut().unwrap().0 = Play::MoveLeft;
					let next = player.move_down();
					let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
					if !visited[i] {
						visited[i] = true;
						if !well.test(&next) {
							path.push((Play::SoftDrop, next));
						}
						else {
							let mut well = well.clone();
							well.etch(&player);
							let score = weights.eval(&well);
							if score > best_score {
								best_score = score;
								best_play.clear();
								best_play.extend(path.iter().map(|&(play, _)| {
									match play {
										Play::MoveLeft => Play::SoftDrop,
										Play::MoveRight => Play::MoveLeft,
										Play::RotateCW => Play::MoveRight,
										Play::RotateCCW => Play::RotateCW,
										Play::SoftDrop => Play::SoftDrop,
										Play::Idle => Play::RotateCCW,
										_ => unreachable!(),
									}
								}));
							}
						}
					}
				},
				Play::MoveLeft => {
					path.last_mut().unwrap().0 = Play::MoveRight;
					let next = player.move_left();
					let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
					if !visited[i] {
						visited[i] = true;
						if !well.test(&next) {
							path.push((Play::SoftDrop, next));
						}
					}
				},
				Play::MoveRight => {
					path.last_mut().unwrap().0 = Play::RotateCW;
					let next = player.move_right();
					let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
					if !visited[i] {
						visited[i] = true;
						if !well.test(&next) {
							path.push((Play::SoftDrop, next));
						}
					}
				},
				Play::RotateCW => {
					path.last_mut().unwrap().0 = Play::RotateCCW;
					let next = player.rotate_cw();
					let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
					if !visited[i] {
						visited[i] = true;
						if !well.test(&next) {
							path.push((Play::SoftDrop, next));
						}
					}
				},
				Play::RotateCCW => {
					path.last_mut().unwrap().0 = Play::Idle;
					let next = player.rotate_ccw();
					let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
					if !visited[i] {
						visited[i] = true;
						if !well.test(&next) {
							path.push((Play::SoftDrop, next));
						}
					}
				},
				_ => unreachable!(),
			}
		}
		(best_score, best_play)
	}
	fn piece(weights: &Weights, well: &Well, piece: Piece) -> f64 {
		// Recursive floodfill to find all the playable states

		// The number of states in a single row:
		// `MAX_WIDTH` plus `3` (for overlap with the well) times `4` (the number of rotations)
		const STRIDE: usize = (MAX_WIDTH + 3) * 4;
		// The number of rows starting all the way up to the top
		const SIZE: usize = STRIDE * (MAX_HEIGHT + 4);
		// Mark every place with a visited flag to know to not recurse in here
		type Visited = [bool; SIZE];
		let mut visited = [false; SIZE];

		// Recursively visit all states
		fn rec(visited: &mut Visited, weights: &Weights, well: &Well, player: Player) -> f64 {
			// Check if the current position has been visited
			let i = (player.pt.y as i32 * STRIDE as i32 + (player.pt.x as i32 + 3) * 4 + player.rot as u8 as i32) as usize;
			// println!("player:{:?} STRIDE:{}", player, STRIDE);
			if visited[i] {
				return f64::NEG_INFINITY;
			}
			visited[i] = true;
			// Test if this is a valid move
			// FIXME! Does not evaluate wall-kicks!
			if well.test(&player) {
				return f64::NEG_INFINITY;
			}
			// Try all possible moves from this location
			let cw = rec(visited, weights, well, player.rotate_cw());
			let ccw = rec(visited, weights, well, player.rotate_ccw());
			let left = rec(visited, weights, well, player.move_left());
			let right = rec(visited, weights, well, player.move_right());
			// Finally try moving one down, and eval well
			let player_down = if well.test(&player.move_down()) {
				let mut well = well.clone();
				well.etch(&player);
				weights.eval(&well)
			}
			else {
				rec(visited, weights, well, player.move_down())
			};
			// Brute force for the highest valued placement
			cw.max(ccw).max(left).max(right).max(player_down)
		}

		let start = Player::new(piece, Rot::Zero, Point::new(well.width() / 2 - 2, well.height() + 3));
		rec(&mut visited, weights, well, start)
	}
	pub fn play(&self, state: &State) -> Play {
		state.player().map(|player| {
			if self.rot != player.rot {
				Play::RotateCW
			}
			else if self.x < player.pt.x {
				Play::MoveLeft
			}
			else if self.x > player.pt.x {
				Play::MoveRight
			}
			else {
				Play::HardDrop
			}
		}).unwrap_or(Play::Idle)
	}
}

#[test]
fn tdd() {
	let well = Well::from_data(10, &[
		0b0000110000,
		0b0111111001,
		0b0110111111,
		0b1111111111,
		0b1110111111,
		0b1111111111,
	]);
	let (heights_sum, lines, holes_sum, bumpiness, stacks) = Weights::crunch(&well);
	assert_eq!(28, heights_sum);
	assert_eq!(2, lines);
	assert_eq!(2, holes_sum);
	assert_eq!(6, bumpiness);
	assert_eq!(1, stacks);
}

#[test]
fn path() {
	let well = Well::from_data(10, &[
		0b0000000000,
		0b0000000000,
		0b0000000000,
		0b0000000000,
		0b1100110000,
		0b1100111111,
	]);
	let path = PlayI::path(&Weights::new(), &well, Player::new(Piece::O, Rot::Zero, Point::new(4, 6)));
	println!("{:#?}", path);
	panic!("catch");
}
<commit_msg>Step 2: Cleanup and commit to the new AI code.<commit_after>/*!
Simple player bot.
*/

use ::std::f64;

use ::{Well, Rot, Piece, Player, Point, MAX_WIDTH, MAX_HEIGHT};

/// Weights for evaluating well.
pub struct Weights {
	/// Factor for the total combined height of all the columns.
	pub agg_height_f: f64,
	/// Factor for the number of completed lines.
	pub complete_lines_f: f64,
	/// Factor for the number of holes in the field.
	pub holes_f: f64,
	/// Factor for the sum of the absolute differences between two adjacent columns.
	pub bumpiness_f: f64,
	/// Factor for the number blocks above a hole.
	pub stacking_f: f64,
}

impl Weights {
	/// Returns some nice weights.
	///
	/// Gently appropriated from https://codemyroad.wordpress.com/2013/04/14/tetris-ai-the-near-perfect-player/
	pub fn new() -> Weights {
		Weights {
			agg_height_f: -0.510066,
			complete_lines_f: 0.0,//0.760666,
			holes_f: -0.35663,
			bumpiness_f: -0.184483,
			stacking_f: -0.5,

			// heights: -0.03,
			// lines: 8.0,
			// holes: -7.5,
			// bumpiness: -3.5,
			// walltouch: 6.52,

			// heights: -3.78,
			// lines: 1.6,
			// holes: -2.31,
			// bumpiness: -0.184483,
			// walltouch: 6.52,
		}
	}
	/// Evaluates a well and returns a score.
	///
	/// The score is the sum of result of each category multiplied by the appropriated multiplier.
	///
	/// This value only has meaning in comparison to other wells.
	/// A higher value indicates a better scoring well.
	pub fn eval(&self, well: &Well) -> f64 {
		// Quick hack to detect game over
		let lines = well.lines();
		let height = well.height() as usize;
		if lines[height - 1] != 0 || lines[height - 2] != 0 {
			return f64::NEG_INFINITY;
		}

		let (agg_height, completed_lines, holes, bumpiness, stacks) = Self::crunch(well);
		return
			self.agg_height_f * agg_height as f64 +
			self.complete_lines_f * completed_lines as f64 +
			self.holes_f * holes as f64 +
			self.bumpiness_f * bumpiness as f64 +
			self.stacking_f * stacks as f64;
	}
	fn crunch(well: &Well) -> (i32, i32, i32, i32, i32) {
		let width = well.width() as usize;
		let mut heights = [0i32; MAX_WIDTH];
		let mut holes = [0i32; MAX_WIDTH];
		let mut stacks = [0i32; MAX_WIDTH];
		let _ = heights[..width];
		let _ = holes[..width];
		let _ = stacks[..width];
		let mut lines = 0;
		let line_mask = well.line_mask();

		let mut height = 0;
		for &line in well.lines() {
			// Skip cleared lines
			if line == line_mask {
				lines += 1;
			}
			else {
				height += 1;
				let mut line = line;
				for col in 0..width {
					if line & 1 != 0 {
						// Sum the holes for this column
						holes[col] += height - heights[col] - 1;
						// Save the height for this column
						heights[col] = height;
						// Save the stacks for this column
						stacks[col] += (holes[col] != 0) as i32;
					}
					line >>= 1;
				}
			}
		}

		let height_sum = heights[..width].iter().sum();
		let holes_sum = holes[..width].iter().sum();
		let stacks_sum = stacks[..width].iter().sum();
		let bumpiness = heights[..width].windows(2).map(|window| (window[0] - window[1]).abs()).sum();

		(height_sum, lines, holes_sum, bumpiness, stacks_sum)
	}
}

/// Player move.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum Play {
	Idle,
	MoveLeft,
	MoveRight,
	RotateCW,
	RotateCCW,
	SoftDrop,
	HardDrop,
}

/// Player AI.
#[derive(Clone, Debug, PartialEq)]
pub struct PlayI {
	pub score: f64,
	pub play: Vec<Play>,
}

impl PlayI {
	/// Calculate the best move with the given weights.
	pub fn play(weights: &Weights, well: &Well, player: Player) -> PlayI {
		// Keep track of which states we've visited
		// TODO! Use a bit array instead, reduces allocation by a factor of 8
		const STRIDE: usize = (MAX_WIDTH + 3) * 4;
		const SIZE: usize = STRIDE * (MAX_HEIGHT + 4);
		let mut visited = [false; SIZE];
		let mut visit = |next: Player| -> bool {
			let i = (next.pt.y as i32 * STRIDE as i32 + (next.pt.x as i32 + 3) * 4 + next.rot as u8 as i32) as usize;
			if !visited[i] {
				visited[i] = true;
				false
			}
			else {
				true
			}
		};
		// Depth-first traversal through the possible game states
		let mut path = Vec::new();
		path.push((Play::Idle, player));
		// Accumulate for the best possible game state
		let mut best = PlayI {
			score: f64::NEG_INFINITY,
			play: Vec::new(),
		};
		// While we have unexplored game states
		while let Some(&(play, player)) = path.last() {
			match play {
				Play::Idle => {
					path.last_mut().unwrap().0 = Play::SoftDrop;
					let next = player.move_down();
					if !visit(next) {
						if !well.test(&next) {
							path.push((Play::Idle, next));
						}
						else {
							let mut well = well.clone();
							well.etch(&player);
							let score = weights.eval(&well);
							if score > best.score {
								best.score = score;
								best.play.clear();
								best.play.extend(path.iter().map(|&(play, _)| play));
							}
						}
					}
				},
				Play::SoftDrop => {
					path.last_mut().unwrap().0 = Play::MoveLeft;
					let next = player.move_left();
					if !visit(next) && !well.test(&next) {
						path.push((Play::Idle, next));
					}
				},
				Play::MoveLeft => {
					path.last_mut().unwrap().0 = Play::MoveRight;
					let next = player.move_right();
					if !visit(next) && !well.test(&next) {
						path.push((Play::Idle, next));
					}
				},
				Play::MoveRight => {
					path.last_mut().unwrap().0 = Play::RotateCW;
					let next = player.rotate_cw();
					if !visit(next) && !well.test(&next) {
						path.push((Play::Idle, next));
					}
				},
				Play::RotateCW => {
					path.last_mut().unwrap().0 = Play::RotateCCW;
					let next = player.rotate_ccw();
					if !visit(next) && !well.test(&next) {
						path.push((Play::Idle, next));
					}
				},
				Play::RotateCCW => {
					// Exhausted all possible moves, back one up and try again
					path.pop();
				},
				_ => unreachable!(),
			}
		}
		best
	}
	/// Brute force the worst piece for the given well and weights.
	pub fn worst_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::S, Piece::Z, Piece::O, Piece::I, Piece::L, Piece::J, Piece::T];
		pieces[..].iter().fold((pieces[0], f64::INFINITY), |(bad_piece, bad_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score < bad_score {
				(piece, score)
			}
			else {
				(bad_piece, bad_score)
			}
		}).0
	}
	/// Brute force the best piece for the given well and weights.
	pub fn best_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::T, Piece::J, Piece::L, Piece::I, Piece::O, Piece::Z, Piece::S];
		pieces[..].iter().fold((pieces[0], f64::NEG_INFINITY), |(good_piece, good_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score > good_score {
				(piece, score)
			}
			else {
				(good_piece, good_score)
			}
		}).0
	}
	fn piece(weights: &Weights, well: &Well, piece: Piece) -> f64 {
		// Recursive floodfill to find all the playable states

		// The number of states in a single row:
		// `MAX_WIDTH` plus `3` (for overlap with the well) times `4` (the number of rotations)
		const STRIDE: usize = (MAX_WIDTH + 3) * 4;
		// The number of rows starting all the way up to the top
		const SIZE: usize = STRIDE * (MAX_HEIGHT + 4);
		// Mark every place with a visited flag to know to not recurse in here
		type Visited = [bool; SIZE];
		let mut visited = [false; SIZE];

		// Recursively visit all states
		fn rec(visited: &mut Visited, weights: &Weights, well: &Well, player: Player) -> f64 {
			// Check if the current position has been visited
			let i = (player.pt.y as i32 * STRIDE as i32 + (player.pt.x as i32 + 3) * 4 + player.rot as u8 as i32) as usize;
			// println!("player:{:?} STRIDE:{}", player, STRIDE);
			if visited[i] {
				return f64::NEG_INFINITY;
			}
			visited[i] = true;
			// Test if this is a valid move
			// FIXME! Does not evaluate wall-kicks!
			if well.test(&player) {
				return f64::NEG_INFINITY;
			}
			// Try all possible moves from this location
			let cw = rec(visited, weights, well, player.rotate_cw());
			let ccw = rec(visited, weights, well, player.rotate_ccw());
			let left = rec(visited, weights, well, player.move_left());
			let right = rec(visited, weights, well, player.move_right());
			// Finally try moving one down, and eval well
			let player_down = if well.test(&player.move_down()) {
				let mut well = well.clone();
				well.etch(&player);
				weights.eval(&well)
			}
			else {
				rec(visited, weights, well, player.move_down())
			};
			// Brute force for the highest valued placement
			cw.max(ccw).max(left).max(right).max(player_down)
		}

		let start = Player::new(piece, Rot::Zero, Point::new(well.width() / 2 - 2, well.height() + 3));
		rec(&mut visited, weights, well, start)
	}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tdd() {
	let well = Well::from_data(10, &[
		0b0000110000,
		0b0111111001,
		0b0110111111,
		0b1111111111,
		0b1110111111,
		0b1111111111,
	]);
	let (heights_sum, lines, holes_sum, bumpiness, stacks) = Weights::crunch(&well);
	assert_eq!(28, heights_sum);
	assert_eq!(2, lines);
	assert_eq!(2, holes_sum);
	assert_eq!(6, bumpiness);
	assert_eq!(1, stacks);
}

#[test]
fn play() {
	let well = Well::from_data(10, &[
		0b0000000000,
		0b0000000000,
		0b0000000000,
		0b0000000000,
		0b1100110000,
		0b1100111111,
	]);
	let bot = PlayI::play(&Weights::new(), &well, Player::new(Piece::O, Rot::Zero, Point::new(4, 6)));
	use Play::*;
	println!("{:#?}", bot);
	assert_eq!(&[SoftDrop, SoftDrop, MoveLeft, MoveLeft, MoveLeft, SoftDrop, SoftDrop, SoftDrop], &*bot.play);
}
}
<|endoftext|>