<commit_before>#![feature(nll)]

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

/*
fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}
*/

fn match_two_phase() {
    let mut x = 3;
    match x {
        ref mut y if { let _val = x; let _val = *y; true } => {},
        _ => (),
    }
}

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;
    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    //two_phase_overlapping1();
    //two_phase_overlapping2();
    match_two_phase();
    with_interior_mutability();
}
<commit_msg>add FIXME<commit_after>#![feature(nll)]

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

/*
fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}
*/

fn match_two_phase() {
    let mut x = 3;
    match x {
        ref mut y if { let _val = x; let _val = *y; true } => {},
        _ => (),
    }
}

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;
    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    match_two_phase();
    with_interior_mutability();
    //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved
    //two_phase_overlapping1();
    //two_phase_overlapping2();
}
<|endoftext|>


<commit_before>//! Library for manipulating Pokémon Gen3 (Fire Red/Leaf Green, Ruby/Emerald/Sapphire) save data.

#![feature(question_mark)]

#[macro_use]
extern crate log;
extern crate byteorder;
extern crate rgen3_string;

mod util {
    mod lower_upper;
    pub use self::lower_upper::LowerUpper;
}
mod rw;

use std::{io, fmt};
use std::fs::File;
use std::error::Error;
use std::path::Path;
use util::LowerUpper;

const UNKNOWN_SAVE_FOOTER_SIZE: usize = 16384;

/// Pokémon Gen3 save data.
pub struct Save {
    blocks: [SaveBlock; 2],
    unknown: [u8; UNKNOWN_SAVE_FOOTER_SIZE],
    most_recent_index: usize,
}

impl fmt::Debug for Save {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.blocks.fmt(f)
    }
}

impl Save {
    /// Load the save data from a file at the provided path.
    pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<Error>> {
        let mut file = File::open(path)?;
        Save::read(&mut file)
    }
    /// Save the save data to a file at the provided path.
    pub fn save_to_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
        let mut file = File::create(path)?;
        self.write(&mut file)
    }
    pub fn sections(&mut self) -> SaveSections {
        let block = &mut self.blocks[self.most_recent_index];
        let sections = &mut block.sections[..];
        let team_and_items = if let SectionData::TeamAndItems(ref mut data) =
                                    sections[block.team_and_items_index].data {
            data
        } else {
            panic!("Unexpected section data. Expected TeamAndItems");
        };
        let trainer_info = if let SectionData::TrainerInfo(ref mut data) =
                                  sections[block.trainer_info_index].data {
            data
        } else {
            panic!("Unexpected section data. Expected TrainerInfo");
        };
        SaveSections {
            team: &mut team_and_items.team,
            trainer: trainer_info,
            pc_boxes: &mut block.pokemon_storage.boxes,
        }
    }
}

pub struct SaveSections<'a> {
    pub trainer: &'a mut TrainerInfo,
    pub team: &'a mut Vec<Pokemon>,
    pub pc_boxes: &'a mut [PokeBox],
}

#[derive(Debug)]
struct SaveBlock {
    sections: Vec<Section>,
    trainer_info_index: usize,
    team_and_items_index: usize,
    // Does not exist yet, meaning the game has only been saved once, and this
    // block hasn't been written over yet.
    nonexistent: bool,
    pokemon_storage: PokemonStorage,
    box_indexes: [usize; N_BOXES],
}

enum SectionData {
    Unimplemented {
        raw: [u8; DATA_SIZE as usize],
        id: u16,
        cksum: u16,
    },
    TrainerInfo(TrainerInfo),
    TeamAndItems(TeamAndItems),
    PcBuffer(PcBuffer),
}

impl fmt::Debug for SectionData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SectionData::Unimplemented { .. } => f.write_str("<Unimplemented section>"),
            SectionData::TrainerInfo(ref data) => data.fmt(f),
            SectionData::TeamAndItems(ref data) => data.fmt(f),
            SectionData::PcBuffer(ref data) => data.fmt(f),
        }
    }
}

#[derive(Debug)]
struct Section {
    data: SectionData,
    unknown_1: u32,
    save_idx: u32,
}

const DATA_SIZE: i64 = 0xFF4;

#[repr(u8)]
#[derive(Clone, Copy, Debug)]
enum Gender {
    Male = 0,
    Female = 1,
}

impl fmt::Display for Gender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str = match *self {
            Gender::Male => "Male",
            Gender::Female => "Female",
        };
        f.write_str(str)
    }
}

#[derive(Debug)]
struct Time {
    hours: u16,
    minutes: u8,
    seconds: u8,
    frames: u8,
}

const TRAINER_INFO_UNKNOWN_3_SIZE: usize = 0x00AC - (0x0013 + 3);
const RS_EM_PLAYERINFO_TRAILING_DATA_SIZE: usize = DATA_SIZE as usize - (0x0AC + 4);
const FRLG_PLAYERINFO_UNKNOWN_CHUNK_SIZE: usize = 0x0AF8 - (0x00AC + 4);
const FRLG_PLAYERINFO_TRAILING_DATA_SIZE: usize = DATA_SIZE as usize - (0x0AF8 + 4);

enum Game {
    RubyOrSapphire { trailing_data: [u8; RS_EM_PLAYERINFO_TRAILING_DATA_SIZE], },
    FireredOrLeafgreen {
        unknown: [u8; FRLG_PLAYERINFO_UNKNOWN_CHUNK_SIZE],
        security_key: u32,
        trailing_data: [u8; FRLG_PLAYERINFO_TRAILING_DATA_SIZE],
    },
    Emerald {
        security_key: u32,
        trailing_data: [u8; RS_EM_PLAYERINFO_TRAILING_DATA_SIZE],
    },
}

#[derive(Clone, Copy)]
enum GameType {
    RubyOrSapphire,
    FireredOrLeafgreen,
    Emerald,
}

impl<'a> From<&'a Game> for GameType {
    fn from(src: &Game) -> Self {
        match *src {
            Game::RubyOrSapphire { .. } => GameType::RubyOrSapphire,
            Game::FireredOrLeafgreen { .. } => GameType::FireredOrLeafgreen,
            Game::Emerald { .. } => GameType::Emerald,
        }
    }
}

impl fmt::Debug for Game {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Game::RubyOrSapphire { .. } => write!(f, "Ruby/Sapphire"),
            Game::FireredOrLeafgreen { security_key, .. } => {
                write!(f, "Fire Red/Leaf Green (security key: {})", security_key)
            }
            Game::Emerald { security_key, .. } => {
                write!(f, "Emerald (security key: {})", security_key)
            }
        }
    }
}

const TRAINER_NAME_LEN: usize = 7;

pub struct TrainerInfo {
    pub name: TrainerName,
    unknown_1: u8,
    gender: Gender,
    unknown_2: u8,
    public_id: u16,
    secret_id: u16,
    time_played: Time,
    options_data: [u8; 3],
    unknown_3: [u8; TRAINER_INFO_UNKNOWN_3_SIZE],
    game: Game,
}

impl TrainerInfo {
    pub fn full_id(&self) -> u32 {
        u32::merge(self.public_id, self.secret_id)
    }
}

impl fmt::Debug for TrainerInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("== Trainer Info ==\n")?;
        writeln!(f, "name: {:?}", self.name)?;
        writeln!(f, "gender: {:?}", self.gender)?;
        writeln!(f,
                 "id: public({:?}) secret({:?}) combined({:?})",
                 self.public_id,
                 self.secret_id,
                 u32::merge(self.public_id, self.secret_id))?;
        writeln!(f, "Time played: {:?}", self.time_played)?;
        writeln!(f, "GAME ID: {:?}", self.game)
    }
}

const EM_RU_SA_TEAMANDITEMS_UNK_LEN: usize = 0x0234;
const FR_LG_TEAMANDITEMS_UNK_LEN: usize = 0x0034;
const TEAMANDITEMS_POKE_LEN: usize = 600;
const EM_RU_SA_TEAMANDITEMS_REM_LEN: usize =
    DATA_SIZE as usize - (EM_RU_SA_TEAMANDITEMS_UNK_LEN + TEAMANDITEMS_POKE_LEN + 4);
const FR_LG_TEAMANDITEMS_REM_LEN: usize = DATA_SIZE as usize -
                                          (FR_LG_TEAMANDITEMS_UNK_LEN + TEAMANDITEMS_POKE_LEN + 4);

enum TeamAndItemsUnknown {
    EmeraldOrRubyOrSapphire([u8; EM_RU_SA_TEAMANDITEMS_UNK_LEN]),
    FireRedOrLeafGreen([u8; FR_LG_TEAMANDITEMS_UNK_LEN]),
}

enum TeamAndItemsRemaining {
    EmeraldOrRubyOrSapphire([u8; EM_RU_SA_TEAMANDITEMS_REM_LEN]),
    FireredOrLeafgreen([u8; FR_LG_TEAMANDITEMS_REM_LEN]),
}

struct TeamAndItems {
    unknown: TeamAndItemsUnknown,
    team: Vec<Pokemon>,
    orig_pokemon_data: [u8; TEAMANDITEMS_POKE_LEN],
    remaining_data: TeamAndItemsRemaining,
}

impl fmt::Debug for TeamAndItems {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("=== Team And Items ===\nTeam listing:\n")?;
        for pokemon in &self.team {
            pokemon.fmt(f)?
        }
        Ok(())
    }
}

const POKEMON_NICK_LEN: usize = 10;

#[derive(Default, Clone, Copy)]
pub struct PokemonNick(pub [u8; POKEMON_NICK_LEN]);
#[derive(Default, Clone, Copy)]
pub struct TrainerName(pub [u8; TRAINER_NAME_LEN]);
#[derive(Default, Clone, Copy)]
pub struct BoxName(pub [u8; BOX_NAME_LEN]);

const BOX_NAME_LEN: usize = 8;

macro_rules! debug_impl {
    ($target:ident) => {
        impl fmt::Debug for $target {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{}", rgen3_string::decode_string(&self.0[..]))
            }
        }
    }
}

debug_impl!(PokemonNick);
debug_impl!(TrainerName);
debug_impl!(BoxName);

/// A Pokemon.
#[derive(Debug, Default)]
#[allow(missing_docs)]
pub struct Pokemon {
    pub personality: u32,
    pub ot_id: u32,
    pub nickname: PokemonNick,
    language: u16,
    pub ot_name: TrainerName,
    markings: u8,
    checksum: u16,
    unknown_1: u16,
    pub data: PokemonData,
    pub active_data: Option<PokemonActiveData>,
}

#[derive(Debug)]
pub struct InvalidSpecies;

impl Pokemon {
    pub fn set_species(&mut self, num: u16) -> Result<(), InvalidSpecies> {
        match num {
            1...251 | 277...411 => {
                self.data.growth.species = num;
                Ok(())
            }
            _ => Err(InvalidSpecies),
        }
    }
}

/// "Active" data that is not stored in the PC boxes.
#[derive(Debug, Default)]
pub struct PokemonActiveData {
    status_condition: u32,
    pub level: u8,
    pokerus_remaining: u8,
    pub current_hp: u16,
    pub total_hp: u16,
    pub attack: u16,
    pub defense: u16,
    pub speed: u16,
    pub sp_attack: u16,
    pub sp_defense: u16,
}

#[derive(Debug,Default)]
pub struct PokemonData {
    pub growth: PokemonGrowth,
    pub attacks: PokemonAttacks,
    pub evs_and_condition: PokemonEvsAndCondition,
    misc: PokemonMisc,
}

#[derive(Debug,Default)]
pub struct PokemonGrowth {
    pub species: u16,
    item_held: u16,
    pub experience: u32,
    pub pp_bonuses: u8,
    pub friendship: u8,
    unknown: u16,
}

#[derive(Debug, Default)]
pub struct PokemonAttacks {
    pub move1: u16,
    pub move2: u16,
    pub move3: u16,
    pub move4: u16,
    pub pp1: u8,
    pub pp2: u8,
    pub pp3: u8,
    pub pp4: u8,
}

#[derive(Debug, Default)]
pub struct PokemonEvsAndCondition {
    pub hp: u8,
    pub attack: u8,
    pub defense: u8,
    pub speed: u8,
    pub sp_attack: u8,
    pub sp_defense: u8,
    pub coolness: u8,
    pub beauty: u8,
    pub cuteness: u8,
    pub smartness: u8,
    pub toughness: u8,
    pub feel: u8,
}

#[derive(Debug, Default)]
struct PokemonMisc {
    pokerus_status: u8,
    met_location: u8,
    origins_info: u16,
    ivs_eggs_and_ability: u32,
    ribbons_and_obedience: u32,
}

struct PcBuffer {
    data: [u8; DATA_SIZE as usize],
    index: usize,
}

impl fmt::Debug for PcBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PC Buffer {}", self.index)
    }
}

const N_BOXES: usize = 14;

#[derive(Default)]
pub struct PokemonStorage {
    current_box: usize,
    boxes: Vec<PokeBox>,
}

impl fmt::Debug for PokemonStorage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pokemon storage: (current box: {})", self.current_box)?;
        for b in &self.boxes {
            b.fmt(f)?;
        }
        Ok(())
    }
}

const N_POKEMON_PER_BOX: usize = 30;

#[derive(Debug,Default)]
pub struct PokeBox {
    name: BoxName,
    wallpaper: u8,
    pub pokemon: [Option<Pokemon>; N_POKEMON_PER_BOX],
}
<commit_msg>Remove question_mark feature attribute<commit_after>//! Library for manipulating Pokémon Gen3 (Fire Red/Leaf Green, Ruby/Emerald/Sapphire) save data.

#[macro_use]
extern crate log;
extern crate byteorder;
extern crate rgen3_string;

mod util {
    mod lower_upper;
    pub use self::lower_upper::LowerUpper;
}
mod rw;

use std::{io, fmt};
use std::fs::File;
use std::error::Error;
use std::path::Path;
use util::LowerUpper;

const UNKNOWN_SAVE_FOOTER_SIZE: usize = 16384;

/// Pokémon Gen3 save data.
pub struct Save {
    blocks: [SaveBlock; 2],
    unknown: [u8; UNKNOWN_SAVE_FOOTER_SIZE],
    most_recent_index: usize,
}

impl fmt::Debug for Save {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.blocks.fmt(f)
    }
}

impl Save {
    /// Load the save data from a file at the provided path.
    pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<Error>> {
        let mut file = File::open(path)?;
        Save::read(&mut file)
    }
    /// Save the save data to a file at the provided path.
    pub fn save_to_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), io::Error> {
        let mut file = File::create(path)?;
        self.write(&mut file)
    }
    pub fn sections(&mut self) -> SaveSections {
        let block = &mut self.blocks[self.most_recent_index];
        let sections = &mut block.sections[..];
        let team_and_items = if let SectionData::TeamAndItems(ref mut data) =
                                    sections[block.team_and_items_index].data {
            data
        } else {
            panic!("Unexpected section data. Expected TeamAndItems");
        };
        let trainer_info = if let SectionData::TrainerInfo(ref mut data) =
                                  sections[block.trainer_info_index].data {
            data
        } else {
            panic!("Unexpected section data. Expected TrainerInfo");
        };
        SaveSections {
            team: &mut team_and_items.team,
            trainer: trainer_info,
            pc_boxes: &mut block.pokemon_storage.boxes,
        }
    }
}

pub struct SaveSections<'a> {
    pub trainer: &'a mut TrainerInfo,
    pub team: &'a mut Vec<Pokemon>,
    pub pc_boxes: &'a mut [PokeBox],
}

#[derive(Debug)]
struct SaveBlock {
    sections: Vec<Section>,
    trainer_info_index: usize,
    team_and_items_index: usize,
    // Does not exist yet, meaning the game has only been saved once, and this
    // block hasn't been written over yet.
    nonexistent: bool,
    pokemon_storage: PokemonStorage,
    box_indexes: [usize; N_BOXES],
}

enum SectionData {
    Unimplemented {
        raw: [u8; DATA_SIZE as usize],
        id: u16,
        cksum: u16,
    },
    TrainerInfo(TrainerInfo),
    TeamAndItems(TeamAndItems),
    PcBuffer(PcBuffer),
}

impl fmt::Debug for SectionData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SectionData::Unimplemented { .. } => f.write_str("<Unimplemented section>"),
            SectionData::TrainerInfo(ref data) => data.fmt(f),
            SectionData::TeamAndItems(ref data) => data.fmt(f),
            SectionData::PcBuffer(ref data) => data.fmt(f),
        }
    }
}

#[derive(Debug)]
struct Section {
    data: SectionData,
    unknown_1: u32,
    save_idx: u32,
}

const DATA_SIZE: i64 = 0xFF4;

#[repr(u8)]
#[derive(Clone, Copy, Debug)]
enum Gender {
    Male = 0,
    Female = 1,
}

impl fmt::Display for Gender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str = match *self {
            Gender::Male => "Male",
            Gender::Female => "Female",
        };
        f.write_str(str)
    }
}

#[derive(Debug)]
struct Time {
    hours: u16,
    minutes: u8,
    seconds: u8,
    frames: u8,
}

const TRAINER_INFO_UNKNOWN_3_SIZE: usize = 0x00AC - (0x0013 + 3);
const RS_EM_PLAYERINFO_TRAILING_DATA_SIZE: usize = DATA_SIZE as usize - (0x0AC + 4);
const FRLG_PLAYERINFO_UNKNOWN_CHUNK_SIZE: usize = 0x0AF8 - (0x00AC + 4);
const FRLG_PLAYERINFO_TRAILING_DATA_SIZE: usize = DATA_SIZE as usize - (0x0AF8 + 4);

enum Game {
    RubyOrSapphire { trailing_data: [u8; RS_EM_PLAYERINFO_TRAILING_DATA_SIZE], },
    FireredOrLeafgreen {
        unknown: [u8; FRLG_PLAYERINFO_UNKNOWN_CHUNK_SIZE],
        security_key: u32,
        trailing_data: [u8; FRLG_PLAYERINFO_TRAILING_DATA_SIZE],
    },
    Emerald {
        security_key: u32,
        trailing_data: [u8; RS_EM_PLAYERINFO_TRAILING_DATA_SIZE],
    },
}

#[derive(Clone, Copy)]
enum GameType {
    RubyOrSapphire,
    FireredOrLeafgreen,
    Emerald,
}

impl<'a> From<&'a Game> for GameType {
    fn from(src: &Game) -> Self {
        match *src {
            Game::RubyOrSapphire { .. } => GameType::RubyOrSapphire,
            Game::FireredOrLeafgreen { .. } => GameType::FireredOrLeafgreen,
            Game::Emerald { .. } => GameType::Emerald,
        }
    }
}

impl fmt::Debug for Game {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Game::RubyOrSapphire { .. } => write!(f, "Ruby/Sapphire"),
            Game::FireredOrLeafgreen { security_key, .. } => {
                write!(f, "Fire Red/Leaf Green (security key: {})", security_key)
            }
            Game::Emerald { security_key, .. } => {
                write!(f, "Emerald (security key: {})", security_key)
            }
        }
    }
}

const TRAINER_NAME_LEN: usize = 7;

pub struct TrainerInfo {
    pub name: TrainerName,
    unknown_1: u8,
    gender: Gender,
    unknown_2: u8,
    public_id: u16,
    secret_id: u16,
    time_played: Time,
    options_data: [u8; 3],
    unknown_3: [u8; TRAINER_INFO_UNKNOWN_3_SIZE],
    game: Game,
}

impl TrainerInfo {
    pub fn full_id(&self) -> u32 {
        u32::merge(self.public_id, self.secret_id)
    }
}

impl fmt::Debug for TrainerInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("== Trainer Info ==\n")?;
        writeln!(f, "name: {:?}", self.name)?;
        writeln!(f, "gender: {:?}", self.gender)?;
        writeln!(f,
                 "id: public({:?}) secret({:?}) combined({:?})",
                 self.public_id,
                 self.secret_id,
                 u32::merge(self.public_id, self.secret_id))?;
        writeln!(f, "Time played: {:?}", self.time_played)?;
        writeln!(f, "GAME ID: {:?}", self.game)
    }
}

const EM_RU_SA_TEAMANDITEMS_UNK_LEN: usize = 0x0234;
const FR_LG_TEAMANDITEMS_UNK_LEN: usize = 0x0034;
const TEAMANDITEMS_POKE_LEN: usize = 600;
const EM_RU_SA_TEAMANDITEMS_REM_LEN: usize =
    DATA_SIZE as usize - (EM_RU_SA_TEAMANDITEMS_UNK_LEN + TEAMANDITEMS_POKE_LEN + 4);
const FR_LG_TEAMANDITEMS_REM_LEN: usize = DATA_SIZE as usize -
                                          (FR_LG_TEAMANDITEMS_UNK_LEN + TEAMANDITEMS_POKE_LEN + 4);

enum TeamAndItemsUnknown {
    EmeraldOrRubyOrSapphire([u8; EM_RU_SA_TEAMANDITEMS_UNK_LEN]),
    FireRedOrLeafGreen([u8; FR_LG_TEAMANDITEMS_UNK_LEN]),
}

enum TeamAndItemsRemaining {
    EmeraldOrRubyOrSapphire([u8; EM_RU_SA_TEAMANDITEMS_REM_LEN]),
    FireredOrLeafgreen([u8; FR_LG_TEAMANDITEMS_REM_LEN]),
}

struct TeamAndItems {
    unknown: TeamAndItemsUnknown,
    team: Vec<Pokemon>,
    orig_pokemon_data: [u8; TEAMANDITEMS_POKE_LEN],
    remaining_data: TeamAndItemsRemaining,
}

impl fmt::Debug for TeamAndItems {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("=== Team And Items ===\nTeam listing:\n")?;
        for pokemon in &self.team {
            pokemon.fmt(f)?
        }
        Ok(())
    }
}

const POKEMON_NICK_LEN: usize = 10;

#[derive(Default, Clone, Copy)]
pub struct PokemonNick(pub [u8; POKEMON_NICK_LEN]);
#[derive(Default, Clone, Copy)]
pub struct TrainerName(pub [u8; TRAINER_NAME_LEN]);
#[derive(Default, Clone, Copy)]
pub struct BoxName(pub [u8; BOX_NAME_LEN]);

const BOX_NAME_LEN: usize = 8;

macro_rules! debug_impl {
    ($target:ident) => {
        impl fmt::Debug for $target {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{}", rgen3_string::decode_string(&self.0[..]))
            }
        }
    }
}

debug_impl!(PokemonNick);
debug_impl!(TrainerName);
debug_impl!(BoxName);

/// A Pokemon.
#[derive(Debug, Default)]
#[allow(missing_docs)]
pub struct Pokemon {
    pub personality: u32,
    pub ot_id: u32,
    pub nickname: PokemonNick,
    language: u16,
    pub ot_name: TrainerName,
    markings: u8,
    checksum: u16,
    unknown_1: u16,
    pub data: PokemonData,
    pub active_data: Option<PokemonActiveData>,
}

#[derive(Debug)]
pub struct InvalidSpecies;

impl Pokemon {
    pub fn set_species(&mut self, num: u16) -> Result<(), InvalidSpecies> {
        match num {
            1...251 | 277...411 => {
                self.data.growth.species = num;
                Ok(())
            }
            _ => Err(InvalidSpecies),
        }
    }
}

/// "Active" data that is not stored in the PC boxes.
#[derive(Debug, Default)]
pub struct PokemonActiveData {
    status_condition: u32,
    pub level: u8,
    pokerus_remaining: u8,
    pub current_hp: u16,
    pub total_hp: u16,
    pub attack: u16,
    pub defense: u16,
    pub speed: u16,
    pub sp_attack: u16,
    pub sp_defense: u16,
}

#[derive(Debug,Default)]
pub struct PokemonData {
    pub growth: PokemonGrowth,
    pub attacks: PokemonAttacks,
    pub evs_and_condition: PokemonEvsAndCondition,
    misc: PokemonMisc,
}

#[derive(Debug,Default)]
pub struct PokemonGrowth {
    pub species: u16,
    item_held: u16,
    pub experience: u32,
    pub pp_bonuses: u8,
    pub friendship: u8,
    unknown: u16,
}

#[derive(Debug, Default)]
pub struct PokemonAttacks {
    pub move1: u16,
    pub move2: u16,
    pub move3: u16,
    pub move4: u16,
    pub pp1: u8,
    pub pp2: u8,
    pub pp3: u8,
    pub pp4: u8,
}

#[derive(Debug, Default)]
pub struct PokemonEvsAndCondition {
    pub hp: u8,
    pub attack: u8,
    pub defense: u8,
    pub speed: u8,
    pub sp_attack: u8,
    pub sp_defense: u8,
    pub coolness: u8,
    pub beauty: u8,
    pub cuteness: u8,
    pub smartness: u8,
    pub toughness: u8,
    pub feel: u8,
}

#[derive(Debug, Default)]
struct PokemonMisc {
    pokerus_status: u8,
    met_location: u8,
    origins_info: u16,
    ivs_eggs_and_ability: u32,
    ribbons_and_obedience: u32,
}

struct PcBuffer {
    data: [u8; DATA_SIZE as usize],
    index: usize,
}

impl fmt::Debug for PcBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PC Buffer {}", self.index)
    }
}

const N_BOXES: usize = 14;

#[derive(Default)]
pub struct PokemonStorage {
    current_box: usize,
    boxes: Vec<PokeBox>,
}

impl fmt::Debug for PokemonStorage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pokemon storage: (current box: {})", self.current_box)?;
        for b in &self.boxes {
            b.fmt(f)?;
        }
        Ok(())
    }
}

const N_POKEMON_PER_BOX: usize = 30;

#[derive(Debug,Default)]
pub struct PokeBox {
    name: BoxName,
    wallpaper: u8,
    pub pokemon: [Option<Pokemon>; N_POKEMON_PER_BOX],
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_export]
macro_rules! size_of_test {
    ($testname: ident, $t: ty, $expected_size: expr) => {
        #[test]
        fn $testname() {
            let new = ::std::mem::size_of::<$t>();
            let old = $expected_size;
            if new < old {
                panic!(
                    "Your changes have decreased the stack size of {} from {} to {}. \
                     Good work! Please update the expected size in {}.",
                    stringify!($t), old, new, file!()
                )
            } else if new > old {
                panic!(
                    "Your changes have increased the stack size of {} from {} to {}. \
                     Please consider choosing a design which avoids this increase. \
                     If you feel that the increase is necessary, update the size in {}.",
                    stringify!($t), old, new, file!()
                )
            }
        }
    }
}
<commit_msg>Auto merge of #21661 - chansuke:format_size_of_test, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_export]
macro_rules! size_of_test {
    ($testname: ident, $t: ty, $expected_size: expr) => {
        #[test]
        fn $testname() {
            let new = ::std::mem::size_of::<$t>();
            let old = $expected_size;
            if new < old {
                panic!(
                    "Your changes have decreased the stack size of {} from {} to {}. \
                     Good work! Please update the expected size in {}.",
                    stringify!($t),
                    old,
                    new,
                    file!()
                )
            } else if new > old {
                panic!(
                    "Your changes have increased the stack size of {} from {} to {}. \
                     Please consider choosing a design which avoids this increase. \
                     If you feel that the increase is necessary, update the size in {}.",
                    stringify!($t),
                    old,
                    new,
                    file!()
                )
            }
        }
    };
}
<|endoftext|>


<commit_before>use rational::Rational;
use complex::Complex;

#[deriving(Eq)]
enum LDatum {
    LIdent(~str),
    LString(~str),
    LChar(char),
    LBool(bool),
    LEComplex(~Complex<Rational>),
    LIComplex(~Complex<f64>),
    LRational(Rational),
    LFloat(f64),
    LInt(int),
}

struct Parser {
    priv reader: @io::Reader,
    priv buf: char,
    priv has_buf: bool,
    line: uint,
    col: uint,
}

pub fn Parser(reader: @io::Reader) -> Parser {
    Parser {
        reader: reader,
        has_buf: false,
        buf: 0 as char,
        line: 1,
        col: 1,
    }
}

priv fn id_init(c: char) -> bool {
    match(c) {
        '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
        _ => false,
    }
}

pub impl Parser {
    fn parse(&mut self) -> Result<LDatum, ~str> {
        do result::chain(self.parse_datum()) |v| {
            self.consume_whitespace();

            if(self.eof()) {
                Ok(v)
            } else {
                Err(~"trailing input")
            }
        }
    }
}

priv impl Parser {
    fn eof(&mut self) -> bool {
        !self.has_buf && self.reader.eof()
    }

    fn consume(&mut self) -> char {
        if(self.has_buf) {
            self.has_buf = false;
        } else {
            self.buf = self.reader.read_char();
        }

        if(self.buf == '\n') {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }

        self.buf
    }

    fn lookahead(&mut self) -> char {
        if(!self.has_buf) {
            self.has_buf = true;
            self.buf = self.reader.read_char();
        }
        self.buf
    }

    fn consume_whitespace(&mut self) {
        while(!self.eof()) {
            match(self.lookahead()) {
                ' '| '\t' | '\r' | '\n' => { self.consume(); },
                ';' =>
                    {
                        self.consume();
                        while(!self.eof() && self.consume() != '\n') { () }
                    },
                _ => break
            }
        }
    }

    fn parse_datum(&mut self) -> Result<LDatum, ~str> {
        self.consume_whitespace();

        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let c = self.lookahead();
        match(c) {
            _ if id_init(c) =>
                Ok(LIdent(self.parse_ident())),
            '"' => {
                    match(self.parse_string()) {
                        Ok(s) => Ok(LString(s)),
                        Err(e) => Err(e),
                    }
                },
            '#' => {
                    self.consume();
                    self.parse_sharp()
                },
            '0'..'9' =>
                self.parse_number(~""),
            _ =>
                Err(~"unexpected character: " + str::from_char(c)),
        }
    }

    fn parse_sharp(&mut self) -> Result<LDatum, ~str> {
        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let c = self.consume();
        match(c) {
            '\\' =>
                match(self.parse_char()) {
                    Ok(x) => Ok(LChar(x)),
                    Err(e) => Err(e),
                },
            't' =>
                Ok(LBool(true)),
            'f' =>
                Ok(LBool(false)),
            'e' | 'i' | 'b' | 'o' | 'd' | 'x' =>
                self.parse_number(~"#" + str::from_char(c)),
            _ =>
                Err(~"unexpected character: " + str::from_char(c)),
        }
    }

    fn parse_char(&mut self) -> Result<char, ~str> {
        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let lit =
        do io::with_str_writer |wr| {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' ' | '\t' | '\r' | '\n' => break,
                    _ => wr.write_char(self.consume()),
                }
            }
        };

        if(lit.len() == 1) {
            Ok(lit.char_at(0))
        } else if(lit == ~"space") {
            Ok(' ')
        } else if(lit == ~"newline") {
            Ok('\n')
        } else {
            Err(~"unknown character literal " + lit)
        }
    }

    fn parse_number(&mut self, init: &str) -> Result<LDatum, ~str> {
        match(self.parse_num_prefix(init)) {
            Err(e) => Err(e),
            Ok((exactness, radix)) => {
                if(self.eof()) {
                    Err(~"unexpected EOF")
                } else {
                    let sign =
                    match(self.lookahead()) {
                        '+' => { self.consume(); true },
                        '-' => { self.consume(); false },
                        _ => true,
                    };

                    let r = match(radix) {
                        None => 10,
                        Some(x) => x,
                    };

                    match(self.parse_ureal(r)) {
                        Err(e) => Err(e),
                        Ok(Left(d)) => Ok(LInt(d)),
                        Ok(Right(f)) => Ok(LRational(f)),
                    }
                }
            }
        }
    }

    fn parse_ureal(&mut self, r: uint) -> Result<Either<int, Rational>, ~str> {
        let (x, xr) = self.parse_radix(r);

        if(x.is_empty()) {
            Err(~"")
        } else {
            match(int::from_str_radix(x, r)) {
                None => Err(~"invalid number literal"),
                Some(z) => {
                    let d = z * num::pow_with_uint(r, xr) as int;
                    if(!self.eof() && self.lookahead() == '/') {
                        self.consume();
                        let (y, yr) = self.parse_radix(r);
                        if(y.is_empty()) {
                            Err(~"invalid rational number")
                        } else {
                            match(int::from_str_radix(y, r)) {
                                None => Err(~"invalid number literal"),
                                Some(z2) => {
                                    let n = z2 * num::pow_with_uint(r, yr) as int;
                                    Ok(Right(Rational::new(d, n)))
                                },
                            }
                        }
                    } else {
                        Ok(Left(d))
                    }
                },
            }
        }
    }

    fn parse_radix(&mut self, radix: uint) -> (~str, uint) {
        let mut sum = ~"";
        let mut sharps = 0u;
        let mut consumed = false;

        while(!self.eof()) {
            let c = self.lookahead();

            if(c == '#' && consumed) {
                while(!self.eof() && self.lookahead() == '#') {
                    sharps += 1u;
                    self.consume();
                }
                break;
            } else if(char::is_digit_radix(c, radix)) {
                consumed = true;
                self.consume();
                sum += str::from_char(c);
            } else {
                break;
            }
        }

        (sum, sharps)
    }

    fn parse_num_prefix(&mut self, init: &str) -> Result<(Option<bool>, Option<uint>), ~str> {
        let mut exactness =
        match(init) {
            "#i" => Some(false),
            "#e" => Some(true),
            _ => None,
        };

        let mut radix =
        match(init) {
            "#b" => Some(2u),
            "#o" => Some(8u),
            "#d" => Some(10u),
            "#x" => Some(16u),
            _ => None,
        };

        if(!self.eof() && self.lookahead() == '#') {
            self.consume();

            if(self.eof()) {
                Err(~"unexpected EOF")
            } else {
                match(self.consume()) {
                    'i' if exactness == None => Ok((Some(false), radix)),
                    'e' if exactness == None => Ok((Some(true), radix)),
                    'i' | 'e' => Err(~"multiple exactness prefix"),
                    'b' if radix == None => Ok((exactness, Some(2u))),
                    'o' if radix == None => Ok((exactness, Some(8u))),
                    'd' if radix == None => Ok((exactness, Some(10u))),
                    'x' if radix == None => Ok((exactness, Some(16u))),
                    'b' | 'o' | 'd' | 'x' => Err(~"multiple radix prefix"),
                    x => Err(~"unexpected prefix #" + str::from_char(x)),
                }
            }
        } else {
            Ok((exactness, radix))
        }
    }

    fn parse_ident(&mut self) -> ~str {
        do io::with_str_writer |wr| {
            while(!self.eof()) {
                let c = self.lookahead();

                match(c) {
                    '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                    _ if id_init(c) => wr.write_char(c),
                    _ => break,
                }

                self.consume();
            }
        }
    }

    fn parse_string(&mut self) -> Result<~str, ~str> {
        let mut escape_fail = false;

        if(self.consume() != '"') {
            fail!(~"internal parser error");
        }

        let val = do io::with_str_writer |wr| {
            while(!self.eof()) {
                let c = self.consume();
                match(c) {
                    '\\' => if self.eof() {
                                escape_fail = true;
                            } else {
                                wr.write_char(self.consume());
                            },
                    '"' => break,
                    _ => wr.write_char(c),
                }
            }
        };

        if(escape_fail) {
            Err(~"unexpected EOF")
        } else {
            Ok(val)
        }
    }
}

#[test]
fn test_parse_ident() {
    let test_src = ~"a3!";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LIdent(~"a3!")));
    }
}

#[test]
fn test_parse_string() {
    let test_src = ~"\"ab\\\"c\"";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LString(~"ab\"c")));
    }
}

#[test]
fn test_parse_char() {
    let test_src = ~"#\\h";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LChar('h')));
    }
}

#[test]
fn test_parse_space() {
    let test_src = ~"#\\space";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LChar(' ')));
    }
}

#[test]
fn test_parse_bool() {
    let test_src = ~"#t";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LBool(true)));
    }
}

#[test]
fn test_parse_int() {
    let test_src = ~"10";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LInt(10)));
    }
}

#[test]
fn test_parse_rational() {
    let test_src = ~"3/6";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LRational(Rational::new(1,2))));
    }
}
<commit_msg>make sure we do not consume after eof<commit_after>use rational::Rational;
use complex::Complex;

#[deriving(Eq)]
enum LDatum {
    LIdent(~str),
    LString(~str),
    LChar(char),
    LBool(bool),
    LEComplex(~Complex<Rational>),
    LIComplex(~Complex<f64>),
    LRational(Rational),
    LFloat(f64),
    LInt(int),
}

struct Parser {
    priv reader: @io::Reader,
    priv buf: char,
    priv has_buf: bool,
    line: uint,
    col: uint,
}

pub fn Parser(reader: @io::Reader) -> Parser {
    Parser {
        reader: reader,
        has_buf: false,
        buf: 0 as char,
        line: 1,
        col: 1,
    }
}

priv fn id_init(c: char) -> bool {
    match(c) {
        '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
        _ => false,
    }
}

pub impl Parser {
    fn parse(&mut self) -> Result<LDatum, ~str> {
        do result::chain(self.parse_datum()) |v| {
            self.consume_whitespace();

            if(self.eof()) {
                Ok(v)
            } else {
                Err(~"trailing input")
            }
        }
    }
}

priv impl Parser {
    fn eof(&mut self) -> bool {
        !self.has_buf && self.reader.eof()
    }

    fn consume(&mut self) -> char {
        if(self.has_buf) {
            self.has_buf = false;
        } else {
            self.buf = self.reader.read_char();
        }

        if(self.buf == '\n') {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }

        self.buf
    }

    fn lookahead(&mut self) -> char {
        if(!self.has_buf) {
            self.has_buf = true;
            self.buf = self.reader.read_char();
        }
        self.buf
    }

    fn consume_whitespace(&mut self) {
        while(!self.eof()) {
            match(self.lookahead()) {
                ' '| '\t' | '\r' | '\n' => { self.consume(); },
                ';' =>
                    {
                        self.consume();
                        while(!self.eof() && self.consume() != '\n') { () }
                    },
                _ => break
            }
        }
    }

    fn parse_datum(&mut self) -> Result<LDatum, ~str> {
        self.consume_whitespace();

        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let c = self.lookahead();
        match(c) {
            _ if id_init(c) =>
                Ok(LIdent(self.parse_ident())),
            '"' => {
                    match(self.parse_string()) {
                        Ok(s) => Ok(LString(s)),
                        Err(e) => Err(e),
                    }
                },
            '#' => {
                    self.consume();
                    self.parse_sharp()
                },
            '0'..'9' =>
                self.parse_number(~""),
            _ =>
                Err(~"unexpected character: " + str::from_char(c)),
        }
    }

    fn parse_sharp(&mut self) -> Result<LDatum, ~str> {
        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let c = self.consume();
        match(c) {
            '\\' =>
                match(self.parse_char()) {
                    Ok(x) => Ok(LChar(x)),
                    Err(e) => Err(e),
                },
            't' =>
                Ok(LBool(true)),
            'f' =>
                Ok(LBool(false)),
            'e' | 'i' | 'b' | 'o' | 'd' | 'x' =>
                self.parse_number(~"#" + str::from_char(c)),
            _ =>
                Err(~"unexpected character: " + str::from_char(c)),
        }
    }

    fn parse_char(&mut self) -> Result<char, ~str> {
        if(self.eof()) {
            return Err(~"unexpected EOF");
        }

        let lit =
        do io::with_str_writer |wr| {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' ' | '\t' | '\r' | '\n' => break,
                    _ => wr.write_char(self.consume()),
                }
            }
        };

        if(lit.len() == 1) {
            Ok(lit.char_at(0))
        } else if(lit == ~"space") {
            Ok(' ')
        } else if(lit == ~"newline") {
            Ok('\n')
        } else {
            Err(~"unknown character literal " + lit)
        }
    }

    fn parse_number(&mut self, init: &str) -> Result<LDatum, ~str> {
        match(self.parse_num_prefix(init)) {
            Err(e) => Err(e),
            Ok((exactness, radix)) => {
                if(self.eof()) {
                    Err(~"unexpected EOF")
                } else {
                    let sign =
                    match(self.lookahead()) {
                        '+' => { self.consume(); true },
                        '-' => { self.consume(); false },
                        _ => true,
                    };

                    let r = match(radix) {
                        None => 10,
                        Some(x) => x,
                    };

                    match(self.parse_ureal(r)) {
                        Err(e) => Err(e),
                        Ok(Left(d)) => Ok(LInt(d)),
                        Ok(Right(f)) => Ok(LRational(f)),
                    }
                }
            }
        }
    }

    fn parse_ureal(&mut self, r: uint) -> Result<Either<int, Rational>, ~str> {
        let (x, xr) = self.parse_radix(r);

        if(x.is_empty()) {
            Err(~"")
        } else {
            match(int::from_str_radix(x, r)) {
                None => Err(~"invalid number literal"),
                Some(z) => {
                    let d = z * num::pow_with_uint(r, xr) as int;
                    if(!self.eof() && self.lookahead() == '/') {
                        self.consume();
                        let (y, yr) = self.parse_radix(r);
                        if(y.is_empty()) {
                            Err(~"invalid rational number")
                        } else {
                            match(int::from_str_radix(y, r)) {
                                None => Err(~"invalid number literal"),
                                Some(z2) => {
                                    let n = z2 * num::pow_with_uint(r, yr) as int;
                                    Ok(Right(Rational::new(d, n)))
                                },
                            }
                        }
                    } else {
                        Ok(Left(d))
                    }
                },
            }
        }
    }

    fn parse_radix(&mut self, radix: uint) -> (~str, uint) {
        let mut sum = ~"";
        let mut sharps = 0u;
        let mut consumed = false;

        while(!self.eof()) {
            let c = self.lookahead();

            if(c == '#' && consumed) {
                while(!self.eof() && self.lookahead() == '#') {
                    sharps += 1u;
                    self.consume();
                }
                break;
            } else if(char::is_digit_radix(c, radix)) {
                consumed = true;
                self.consume();
                sum += str::from_char(c);
            } else {
                break;
            }
        }

        (sum, sharps)
    }

    fn parse_num_prefix(&mut self, init: &str) -> Result<(Option<bool>, Option<uint>), ~str> {
        let mut exactness =
        match(init) {
            "#i" => Some(false),
            "#e" => Some(true),
            _ => None,
        };

        let mut radix =
        match(init) {
            "#b" => Some(2u),
            "#o" => Some(8u),
            "#d" => Some(10u),
            "#x" => Some(16u),
            _ => None,
        };

        if(!self.eof() && self.lookahead() == '#') {
            self.consume();

            if(self.eof()) {
                Err(~"unexpected EOF")
            } else {
                match(self.consume()) {
                    'i' if exactness == None => Ok((Some(false), radix)),
                    'e' if exactness == None => Ok((Some(true), radix)),
                    'i' | 'e' => Err(~"multiple exactness prefix"),
                    'b' if radix == None => Ok((exactness, Some(2u))),
                    'o' if radix == None => Ok((exactness, Some(8u))),
                    'd' if radix == None => Ok((exactness, Some(10u))),
                    'x' if radix == None => Ok((exactness, Some(16u))),
                    'b' | 'o' | 'd' | 'x' => Err(~"multiple radix prefix"),
                    x => Err(~"unexpected prefix #" + str::from_char(x)),
                }
            }
        } else {
            Ok((exactness, radix))
        }
    }

    fn parse_ident(&mut self) -> ~str {
        do io::with_str_writer |wr| {
            while(!self.eof()) {
                let c = self.lookahead();

                match(c) {
                    '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                    _ if id_init(c) => wr.write_char(c),
                    _ => break,
                }

                self.consume();
            }
        }
    }

    fn parse_string(&mut self) -> Result<~str, ~str> {
        let mut escape_fail = false;

        if(self.eof() || self.consume() != '"') {
            fail!(~"internal parser error");
        }

        let val = do io::with_str_writer |wr| {
            while(!self.eof()) {
                let c = self.consume();
                match(c) {
                    '\\' => if self.eof() {
                                escape_fail = true;
                            } else {
                                wr.write_char(self.consume());
                            },
                    '"' => break,
                    _ => wr.write_char(c),
                }
            }
        };

        if(escape_fail) {
            Err(~"unexpected EOF")
        } else {
            Ok(val)
        }
    }
}

#[test]
fn test_parse_ident() {
    let test_src = ~"a3!";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LIdent(~"a3!")));
    }
}

#[test]
fn test_parse_string() {
    let test_src = ~"\"ab\\\"c\"";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LString(~"ab\"c")));
    }
}

#[test]
fn test_parse_char() {
    let test_src = ~"#\\h";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LChar('h')));
    }
}

#[test]
fn test_parse_space() {
    let test_src = ~"#\\space";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LChar(' ')));
    }
}

#[test]
fn test_parse_bool() {
    let test_src = ~"#t";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LBool(true)));
    }
}

#[test]
fn test_parse_int() {
    let test_src = ~"10";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LInt(10)));
    }
}

#[test]
fn test_parse_rational() {
    let test_src = ~"3/6";

    do io::with_str_reader(test_src) |rdr| {
        let mut parser = Parser(rdr);
        let val = parser.parse();
        assert_eq!(val, Ok(LRational(Rational::new(1,2))));
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::HashMap;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_after(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac > bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_after(clock_b) {
            return Relation::After;
        }
        if clock_b.happened_after(self) {
            return Relation::Before;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&mut self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_after(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_after(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
}
<commit_msg>learn_from function for vector clock<commit_after>use std::hash::Hash;
use std::collections::HashMap;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_after(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                // We only check servers that existed in the clock
                // Because we can't tell sequences from missing servers
                if ac > bc {return true;}
            }
        }
        return false;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_after(clock_b) {
            return Relation::After;
        }
        if clock_b.happened_after(self) {
            return Relation::Before;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&mut self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_after(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_after(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
}
<|endoftext|>


<commit_before>use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::{IronResult, status};
use iron::modifier::Modifier;
use iron;
use mount;
use router::{Router, url_for};
use staticfile::{Cache, Static};

use web_server::api;
use web_server::pages;
use web_server::server::RequestTimer;

use std::collections::HashMap;
use std::path::Path;
use std::time::Duration;

fn request_timing(req: &mut Request) -> IronResult<Response> {
    let request_id = req.extensions.get::<Router>().unwrap().find("request_id").unwrap();
    let request_timer = req.extensions.get::<RequestTimer>().unwrap();

    let time_str = request_id.parse::<i32>().ok()
        .and_then(|r_id| request_timer.timings.lock().expect("Poison error")
                            .iter().find(|&&(req_id, _, _)| req_id == r_id)
                            .map(|&(_, time, _)| format!("{:.3} ms", time as f64 / 1000f64)))
        .unwrap_or("?".to_owned());

    Ok(Response::with((status::Ok, time_str)))
}

// fn redirect_to_clusters_page(req: &mut Request) -> IronResult<Response> {
//     let request_url = req.url.clone().into_generic_url();
//     let new_url = request_url.join("/clusters/").unwrap();
//     Ok(Response::with((status::Found, Redirect(iron::Url::from_generic_url(new_url).unwrap()))))
// }

// fn redirect_to2(dest: &str) -> Box<Fn(&mut Request) -> IronResult<Response>> {
//     let dest_owned = dest.to_owned();
//     Box::new(move |req| {
//         let request_url = req.url.clone().into_generic_url();
//         let new_url = request_url.join(&dest_owned).unwrap();
//         Ok(Response::with((status::Found, Redirect(iron::Url::from_generic_url(new_url).unwrap()))))
//     })
//}

fn redirect_to(dest: &str) -> impl Handler {
    let dest_owned = dest.to_owned();
    move |req: &mut Request| {
        let dest_url = url_for(req, &dest_owned, HashMap::new());
        Ok(Response::with((status::Found, Redirect(dest_url))))
    }
}

pub fn chain() -> iron::Chain {
    let mut router = Router::new();
    // router.get("/", redirect_to("clusters"), "home");
    router.get("/clusters", pages::clusters_page, "clusters");
    router.get("/cluster/:cluster_id", pages::cluster_page, "cluster");
    router.get("/cluster/:cluster_id/topic/:topic_name", pages::topic_page, "topic");
    router.get("/cluster/:cluster_id/group/:group_name", pages::group_page, "group");

    // search
    router.get("/topics", pages::topic_search, "topics");
    router.get("/consumers", pages::consumer_search, "consumers");

    // Various
    router.get("/public/*", AssetsHandler::new("/public/", "resources/web_server/public/"), "public_assets");
    router.get("/meta/request_time/:request_id/", request_timing, "request_timing");

    // API
    router.get("/api/cluster/:cluster_id/brokers", api::cluster_brokers, "api_cluster_brokers");
    router.get("/api/cluster/:cluster_id/topics", api::cluster_topics, "api_cluster_topics");
    router.get("/api/cluster/:cluster_id/groups", api::cluster_groups, "api_cluster_groups");
    router.get("/api/cluster/:cluster_id/topic/:topic_name/topology", api::topic_topology, "api_topic_topology");
    router.get("/api/cluster/:cluster_id/topic/:topic_name/groups", api::topic_groups, "api_topic_groups");
    router.get("/api/cluster/:cluster_id/group/:group_name/members", api::group_members, "api_group_members");
    router.get("/api/cluster/:cluster_id/group/:group_name/offsets", api::group_offsets, "api_group_offsets");
    router.get("/api/search/topic", api::topic_search, "api_topic_search");
    router.get("/api/search/consumer", api::consumer_search, "api_consumer_search");

    // todo
    router.get("/brokers", pages::todo, "brokers");
    router.get("/cluster/:cluster_id/broker/:broker_id", pages::todo, "broker");
    iron::Chain::new(router)
}

struct AssetsHandler;

impl AssetsHandler {
    pub fn new(prefix: &str, mount_path: &str) -> mount::Mount {
        let mut assets_mount = mount::Mount::new();
        let mut static_files = Static::new(Path::new(mount_path));
        // static_files.modify(Cache::new(Duration::from_seconds(120)));
        let cache = Cache::new(Duration::from_secs(120));
        cache.modify(&mut static_files);
        assets_mount.mount(prefix, static_files);
        assets_mount
    }
}

#[cfg(test)]
mod chain_tests {

    extern crate router;
    extern crate iron;
    extern crate iron_test;

    use iron::Headers;
    use iron::response::{Response, ResponseBody};
    use iron::status::Status;

    #[test]
    fn get_javascript_responds_correctly() {
        let expected_body = include_str!("public/javascripts/main.js");
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000/public/javascripts/main.js",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status);
        assert_eq!(expected_body, response_body(response).unwrap());
    }

    #[test]
    fn get_css_resonds_correctly() {
        let expected_body = include_str!("public/stylesheets/main.css");
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000/public/stylesheets/main.css",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status);
        assert_eq!(expected_body, response_body(response).unwrap());
    }

    // #[test]
    // fn post_new_task_resonds_with_200() {
    //     let chain = super::chain();
    //     let response = iron_test::request::post(
    //         "http://localhost:3000/new_task",
    //         Headers::new(),
    //         "",
    //         &chain
    //     ).unwrap();

    //     assert_eq!(Some(Status::Ok), response.status)
    // }

    #[test]
    fn get_root_responds_with_200() {
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status)
    }

    fn response_body(response: Response) -> Option<String> {
        if let Some(mut body) = response.body {
            let mut buf = Vec::new();
            body.write_body(&mut ResponseBody::new(&mut buf)).unwrap();
            Some(String::from_utf8(buf).unwrap())
        } else {
            None
        }
    }
}
<commit_msg>Fix routing to root address<commit_after>use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::{IronResult, status};
use iron::modifier::Modifier;
use iron;
use mount;
use router::{Router, url_for};
use staticfile::{Cache, Static};

use web_server::api;
use web_server::pages;
use web_server::server::RequestTimer;

use std::collections::HashMap;
use std::path::Path;
use std::time::Duration;

fn request_timing(req: &mut Request) -> IronResult<Response> {
    let request_id = req.extensions.get::<Router>().unwrap().find("request_id").unwrap();
    let request_timer = req.extensions.get::<RequestTimer>().unwrap();

    let time_str = request_id.parse::<i32>().ok()
        .and_then(|r_id| request_timer.timings.lock().expect("Poison error")
                            .iter().find(|&&(req_id, _, _)| req_id == r_id)
                            .map(|&(_, time, _)| format!("{:.3} ms", time as f64 / 1000f64)))
        .unwrap_or("?".to_owned());

    Ok(Response::with((status::Ok, time_str)))
}

// fn redirect_to_clusters_page(req: &mut Request) -> IronResult<Response> {
//     let request_url = req.url.clone().into_generic_url();
//     let new_url = request_url.join("/clusters/").unwrap();
//     Ok(Response::with((status::Found, Redirect(iron::Url::from_generic_url(new_url).unwrap()))))
// }

// fn redirect_to2(dest: &str) -> Box<Fn(&mut Request) -> IronResult<Response>> {
//     let dest_owned = dest.to_owned();
//     Box::new(move |req| {
//         let request_url = req.url.clone().into_generic_url();
//         let new_url = request_url.join(&dest_owned).unwrap();
//         Ok(Response::with((status::Found, Redirect(iron::Url::from_generic_url(new_url).unwrap()))))
//     })
//}

fn redirect_to(dest: &str) -> impl Handler {
    let dest_owned = dest.to_owned();
    move |req: &mut Request| {
        let dest_url = url_for(req, &dest_owned, HashMap::new());
        Ok(Response::with((status::Found, Redirect(dest_url))))
    }
}

pub fn chain() -> iron::Chain {
    let mut router = Router::new();
    router.get("/", redirect_to("clusters"), "home");
    router.get("/clusters", pages::clusters_page, "clusters");
    router.get("/cluster/:cluster_id", pages::cluster_page, "cluster");
    router.get("/cluster/:cluster_id/topic/:topic_name", pages::topic_page, "topic");
    router.get("/cluster/:cluster_id/group/:group_name", pages::group_page, "group");

    // search
    router.get("/topics", pages::topic_search, "topics");
    router.get("/consumers", pages::consumer_search, "consumers");

    // Various
    router.get("/public/*", AssetsHandler::new("/public/", "resources/web_server/public/"), "public_assets");
    router.get("/meta/request_time/:request_id/", request_timing, "request_timing");

    // API
    router.get("/api/cluster/:cluster_id/brokers", api::cluster_brokers, "api_cluster_brokers");
    router.get("/api/cluster/:cluster_id/topics", api::cluster_topics, "api_cluster_topics");
    router.get("/api/cluster/:cluster_id/groups", api::cluster_groups, "api_cluster_groups");
    router.get("/api/cluster/:cluster_id/topic/:topic_name/topology", api::topic_topology, "api_topic_topology");
    router.get("/api/cluster/:cluster_id/topic/:topic_name/groups", api::topic_groups, "api_topic_groups");
    router.get("/api/cluster/:cluster_id/group/:group_name/members", api::group_members, "api_group_members");
    router.get("/api/cluster/:cluster_id/group/:group_name/offsets", api::group_offsets, "api_group_offsets");
    router.get("/api/search/topic", api::topic_search, "api_topic_search");
    router.get("/api/search/consumer", api::consumer_search, "api_consumer_search");

    // todo
    router.get("/brokers", pages::todo, "brokers");
    router.get("/cluster/:cluster_id/broker/:broker_id", pages::todo, "broker");
    iron::Chain::new(router)
}

struct AssetsHandler;

impl AssetsHandler {
    pub fn new(prefix: &str, mount_path: &str) -> mount::Mount {
        let mut assets_mount = mount::Mount::new();
        let mut static_files = Static::new(Path::new(mount_path));
        // static_files.modify(Cache::new(Duration::from_seconds(120)));
        let cache = Cache::new(Duration::from_secs(120));
        cache.modify(&mut static_files);
        assets_mount.mount(prefix, static_files);
        assets_mount
    }
}

#[cfg(test)]
mod chain_tests {

    extern crate router;
    extern crate iron;
    extern crate iron_test;

    use iron::Headers;
    use iron::response::{Response, ResponseBody};
    use iron::status::Status;

    #[test]
    fn get_javascript_responds_correctly() {
        let expected_body = include_str!("public/javascripts/main.js");
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000/public/javascripts/main.js",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status);
        assert_eq!(expected_body, response_body(response).unwrap());
    }

    #[test]
    fn get_css_resonds_correctly() {
        let expected_body = include_str!("public/stylesheets/main.css");
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000/public/stylesheets/main.css",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status);
        assert_eq!(expected_body, response_body(response).unwrap());
    }

    // #[test]
    // fn post_new_task_resonds_with_200() {
    //     let chain = super::chain();
    //     let response = iron_test::request::post(
    //         "http://localhost:3000/new_task",
    //         Headers::new(),
    //         "",
    //         &chain
    //     ).unwrap();

    //     assert_eq!(Some(Status::Ok), response.status)
    // }

    #[test]
    fn get_root_responds_with_200() {
        let chain = super::chain();
        let response = iron_test::request::get(
            "http://localhost:3000",
            Headers::new(),
            &chain
        ).unwrap();

        assert_eq!(Some(Status::Ok), response.status)
    }

    fn response_body(response: Response) -> Option<String> {
        if let Some(mut body) = response.body {
            let mut buf = Vec::new();
            body.write_body(&mut ResponseBody::new(&mut buf)).unwrap();
            Some(String::from_utf8(buf).unwrap())
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use ffi;

use AsLua;
use AsMutLua;

use Push;
use PushGuard;
use PushOne;
use LuaRead;
use Void;

#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AnyLuaString(pub Vec<u8>);

/// Represents any value that can be stored by Lua
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AnyHashableLuaValue {
    LuaString(String),
    LuaAnyString(AnyLuaString),
    LuaNumber(i32),
    LuaBoolean(bool),
    LuaArray(Vec<(AnyHashableLuaValue, AnyHashableLuaValue)>),
    LuaNil,

    /// The "Other" element is (hopefully) temporary and will be replaced by "Function" and "Userdata".
    /// A panic! will trigger if you try to push a Other.
    LuaOther,
}

/// Represents any value that can be stored by Lua
#[derive(Clone, Debug, PartialEq)]
pub enum AnyLuaValue {
    LuaString(String),
    LuaAnyString(AnyLuaString),
    LuaNumber(f64),
    LuaBoolean(bool),
    LuaArray(Vec<(AnyLuaValue, AnyLuaValue)>),
    LuaNil,

    /// The "Other" element is (hopefully) temporary and will be replaced by "Function" and "Userdata".
    /// A panic! will trigger if you try to push a Other.
    LuaOther,
}

impl<'lua, L> Push<L> for AnyLuaValue
    where L: AsMutLua<'lua>
{
    type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)

    #[inline]
    fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
        let raw_lua = lua.as_lua();
        match self {
            AnyLuaValue::LuaString(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaNumber(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaArray(val) => {
                // Pushing a `Vec<(AnyLuaValue, AnyLuaValue)>` on a `L` requires calling the
                // function that pushes a `AnyLuaValue` on a `&mut L`, which in turns requires
                // calling the function that pushes a `AnyLuaValue` on a `&mut &mut L`, and so on.
                // In order to avoid this infinite recursion, we push the array on a
                // `&mut AsMutLua` instead.

                // We also need to destroy and recreate the push guard, otherwise the type parameter
                // doesn't match.
                let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();

                Ok(PushGuard {
                    lua: lua,
                    size: size,
                    raw_lua: raw_lua,
                })
            }
            AnyLuaValue::LuaNil => {
                unsafe {
                    ffi::lua_pushnil(lua.as_mut_lua().0);
                }
                Ok(PushGuard {
                    lua: lua,
                    size: 1,
                    raw_lua: raw_lua,
                })
            } // Use ffi::lua_pushnil.
            AnyLuaValue::LuaOther => panic!("can't push a AnyLuaValue of type Other"),
        }
    }
}

impl<'lua, L> PushOne<L> for AnyLuaValue where L: AsMutLua<'lua> {}

impl<'lua, L> LuaRead<L> for AnyLuaValue
    where L: AsLua<'lua>
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<AnyLuaValue, L> {
        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyLuaValue::LuaNumber(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyLuaValue::LuaBoolean(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyLuaValue::LuaString(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyLuaValue::LuaAnyString(v)),
            Err(lua) => lua,
        };

        if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
            return Ok(AnyLuaValue::LuaNil);
        }

        // let _lua = match LuaRead::lua_read_at_position(&lua, index) {
        // Ok(v) => return Ok(AnyLuaValue::LuaArray(v)),
        // Err(lua) => lua
        // };

        Ok(AnyLuaValue::LuaOther)
    }
}

impl<'lua, L> Push<L> for AnyHashableLuaValue
    where L: AsMutLua<'lua>
{
    type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)

    #[inline]
    fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
        let raw_lua = lua.as_lua();
        match self {
            AnyHashableLuaValue::LuaString(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaNumber(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaArray(val) => {
                // Pushing a `Vec<(AnyHashableLuaValue, AnyHashableLuaValue)>` on a `L` requires calling the
                // function that pushes a `AnyHashableLuaValue` on a `&mut L`, which in turns requires
                // calling the function that pushes a `AnyHashableLuaValue` on a `&mut &mut L`, and so on.
                // In order to avoid this infinite recursion, we push the array on a
                // `&mut AsMutLua` instead.

                // We also need to destroy and recreate the push guard, otherwise the type parameter
                // doesn't match.
                let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();

                Ok(PushGuard {
                    lua: lua,
                    size: size,
                    raw_lua: raw_lua,
                })
            }
            AnyHashableLuaValue::LuaNil => {
                unsafe {
                    ffi::lua_pushnil(lua.as_mut_lua().0);
                }
                Ok(PushGuard {
                    lua: lua,
                    size: 1,
                    raw_lua: raw_lua,
                })
            } // Use ffi::lua_pushnil.
            AnyHashableLuaValue::LuaOther => panic!("can't push a AnyHashableLuaValue of type Other"),
        }
    }
}

impl<'lua, L> PushOne<L> for AnyHashableLuaValue where L: AsMutLua<'lua> {}

impl<'lua, L> LuaRead<L> for AnyHashableLuaValue
    where L: AsLua<'lua>
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<AnyHashableLuaValue, L> {
        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaNumber(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaBoolean(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaString(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaAnyString(v)),
            Err(lua) => lua,
        };

        if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
            return Ok(AnyHashableLuaValue::LuaNil);
        }

        // let _lua = match LuaRead::lua_read_at_position(&lua, index) {
        // Ok(v) => return Ok(AnyHashableLuaValue::LuaArray(v)),
        // Err(lua) => lua
        // };

        Ok(AnyHashableLuaValue::LuaOther)
    }
}

#[cfg(test)]
mod tests {
    use Lua;
    use AnyLuaValue;
    use AnyHashableLuaValue;
    use AnyLuaString;

    #[test]
    fn read_numbers() {
        let mut lua = Lua::new();

        lua.set("a", "-2");
        lua.set("b", 3.5f32);

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaNumber(-2.0));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaNumber(3.5));
    }

    #[test]
    fn read_hashable_numbers() {
        let mut lua = Lua::new();

        lua.set("a", "-2");
        lua.set("b", "4");

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaNumber(-2));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaNumber(4));
    }

    #[test]
    fn read_strings() {
        let mut lua = Lua::new();

        lua.set("a", "hello");
        lua.set("b", "3x");
        lua.set("c", "false");

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaString("hello".to_string()));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaString("3x".to_string()));

        let z: AnyLuaValue = lua.get("c").unwrap();
        assert_eq!(z, AnyLuaValue::LuaString("false".to_string()));
    }

    #[test]
    fn read_hashable_strings() {
        let mut lua = Lua::new();

        lua.set("a", "hello");
        lua.set("b", "3x");
        lua.set("c", "false");

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaString("hello".to_string()));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaString("3x".to_string()));

        let z: AnyHashableLuaValue = lua.get("c").unwrap();
        assert_eq!(z, AnyHashableLuaValue::LuaString("false".to_string()));
    }

    #[test]
    fn read_booleans() {
        let mut lua = Lua::new();

        lua.set("a", true);
        lua.set("b", false);

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaBoolean(true));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaBoolean(false));
    }

    #[test]
    fn read_hashable_booleans() {
        let mut lua = Lua::new();

        lua.set("a", true);
        lua.set("b", false);

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaBoolean(true));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaBoolean(false));
    }

    #[test]
    fn push_numbers() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaNumber(3.0));

        let x: i32 = lua.get("a").unwrap();
        assert_eq!(x, 3);
    }

    #[test]
    fn push_hashable_numbers() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaNumber(3));

        let x: i32 = lua.get("a").unwrap();
        assert_eq!(x, 3);
    }

    #[test]
    fn push_strings() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaString("hello".to_string()));

        let x: String = lua.get("a").unwrap();
        assert_eq!(x, "hello");
    }

    #[test]
    fn push_hashable_strings() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaString("hello".to_string()));

        let x: String = lua.get("a").unwrap();
        assert_eq!(x, "hello");
    }

    #[test]
    fn push_booleans() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaBoolean(true));

        let x: bool = lua.get("a").unwrap();
        assert_eq!(x, true);
    }

    #[test]
    fn push_hashable_booleans() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaBoolean(true));

        let x: bool = lua.get("a").unwrap();
        assert_eq!(x, true);
    }

    #[test]
    fn push_nil() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaNil);

        let x: Option<i32> = lua.get("a");
        assert!(x.is_none(),
                "x is a Some value when it should be a None value. X: {:?}",
                x);
    }

    #[test]
    fn push_hashable_nil() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaNil);

        let x: Option<i32> = lua.get("a");
        assert!(x.is_none(),
                "x is a Some value when it should be a None value. X: {:?}",
                x);
    }

    #[test]
    fn non_utf_8_string() {
        let mut lua = Lua::new();
        let a = lua.execute::<AnyLuaValue>(r"return '\xff\xfe\xff\xfe'").unwrap();
        match a {
            AnyLuaValue::LuaAnyString(AnyLuaString(v)) => {
                assert_eq!(Vec::from(&b"\xff\xfe\xff\xfe"[..]), v);
            },
            _ => panic!("Decoded to wrong variant"),
        }
    }
}
<commit_msg>AnyLuaValue always reads strings as strings, even if they could be parsed as numbers (fix #170)<commit_after>use ffi;

use AsLua;
use AsMutLua;

use Push;
use PushGuard;
use PushOne;
use LuaRead;
use Void;

#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AnyLuaString(pub Vec<u8>);

/// Represents any value that can be stored by Lua
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AnyHashableLuaValue {
    LuaString(String),
    LuaAnyString(AnyLuaString),
    LuaNumber(i32),
    LuaBoolean(bool),
    LuaArray(Vec<(AnyHashableLuaValue, AnyHashableLuaValue)>),
    LuaNil,

    /// The "Other" element is (hopefully) temporary and will be replaced by "Function" and "Userdata".
    /// A panic! will trigger if you try to push a Other.
    LuaOther,
}

/// Represents any value that can be stored by Lua
#[derive(Clone, Debug, PartialEq)]
pub enum AnyLuaValue {
    LuaString(String),
    LuaAnyString(AnyLuaString),
    LuaNumber(f64),
    LuaBoolean(bool),
    LuaArray(Vec<(AnyLuaValue, AnyLuaValue)>),
    LuaNil,

    /// The "Other" element is (hopefully) temporary and will be replaced by "Function" and "Userdata".
    /// A panic! will trigger if you try to push a Other.
    LuaOther,
}

impl<'lua, L> Push<L> for AnyLuaValue
    where L: AsMutLua<'lua>
{
    type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)

    #[inline]
    fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
        let raw_lua = lua.as_lua();
        match self {
            AnyLuaValue::LuaString(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaNumber(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
            AnyLuaValue::LuaArray(val) => {
                // Pushing a `Vec<(AnyLuaValue, AnyLuaValue)>` on a `L` requires calling the
                // function that pushes a `AnyLuaValue` on a `&mut L`, which in turns requires
                // calling the function that pushes a `AnyLuaValue` on a `&mut &mut L`, and so on.
                // In order to avoid this infinite recursion, we push the array on a
                // `&mut AsMutLua` instead.

                // We also need to destroy and recreate the push guard, otherwise the type parameter
                // doesn't match.
                let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();

                Ok(PushGuard {
                    lua: lua,
                    size: size,
                    raw_lua: raw_lua,
                })
            }
            AnyLuaValue::LuaNil => {
                unsafe {
                    ffi::lua_pushnil(lua.as_mut_lua().0);
                }
                Ok(PushGuard {
                    lua: lua,
                    size: 1,
                    raw_lua: raw_lua,
                })
            } // Use ffi::lua_pushnil.
            AnyLuaValue::LuaOther => panic!("can't push a AnyLuaValue of type Other"),
        }
    }
}

impl<'lua, L> PushOne<L> for AnyLuaValue where L: AsMutLua<'lua> {}

impl<'lua, L> LuaRead<L> for AnyLuaValue
    where L: AsLua<'lua>
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<AnyLuaValue, L> {

        // If we know that the value on the stack is a string, we should try
        // to parse it as a string instead of a number or boolean, so that
        // values such as '1.10' don't become `AnyLuaValue::LuaNumber(1.1)`.
        let data_type = unsafe { ffi::lua_type(lua.as_lua().0, index) };
        if data_type == ffi::LUA_TSTRING {

            let lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaString(v)),
                Err(lua) => lua,
            };

            let _lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaAnyString(v)),
                Err(lua) => lua,
            };

            Ok(AnyLuaValue::LuaOther)

        } else {

            let lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaNumber(v)),
                Err(lua) => lua,
            };

            let lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaBoolean(v)),
                Err(lua) => lua,
            };

            let lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaString(v)),
                Err(lua) => lua,
            };

            let lua = match LuaRead::lua_read_at_position(&lua, index) {
                Ok(v) => return Ok(AnyLuaValue::LuaAnyString(v)),
                Err(lua) => lua,
            };

            if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
                return Ok(AnyLuaValue::LuaNil);
            }

            // let _lua = match LuaRead::lua_read_at_position(&lua, index) {
            // Ok(v) => return Ok(AnyLuaValue::LuaArray(v)),
            // Err(lua) => lua
            // };

            Ok(AnyLuaValue::LuaOther)
        }
    }
}

impl<'lua, L> Push<L> for AnyHashableLuaValue
    where L: AsMutLua<'lua>
{
    type Err = Void;      // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)

    #[inline]
    fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
        let raw_lua = lua.as_lua();
        match self {
            AnyHashableLuaValue::LuaString(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaAnyString(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaNumber(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaBoolean(val) => val.push_to_lua(lua),
            AnyHashableLuaValue::LuaArray(val) => {
                // Pushing a `Vec<(AnyHashableLuaValue, AnyHashableLuaValue)>` on a `L` requires calling the
                // function that pushes a `AnyHashableLuaValue` on a `&mut L`, which in turns requires
                // calling the function that pushes a `AnyHashableLuaValue` on a `&mut &mut L`, and so on.
                // In order to avoid this infinite recursion, we push the array on a
                // `&mut AsMutLua` instead.

                // We also need to destroy and recreate the push guard, otherwise the type parameter
                // doesn't match.
                let size = val.push_no_err(&mut lua as &mut AsMutLua<'lua>).forget_internal();

                Ok(PushGuard {
                    lua: lua,
                    size: size,
                    raw_lua: raw_lua,
                })
            }
            AnyHashableLuaValue::LuaNil => {
                unsafe {
                    ffi::lua_pushnil(lua.as_mut_lua().0);
                }
                Ok(PushGuard {
                    lua: lua,
                    size: 1,
                    raw_lua: raw_lua,
                })
            } // Use ffi::lua_pushnil.
            AnyHashableLuaValue::LuaOther => panic!("can't push a AnyHashableLuaValue of type Other"),
        }
    }
}

impl<'lua, L> PushOne<L> for AnyHashableLuaValue where L: AsMutLua<'lua> {}

impl<'lua, L> LuaRead<L> for AnyHashableLuaValue
    where L: AsLua<'lua>
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<AnyHashableLuaValue, L> {
        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaNumber(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaBoolean(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaString(v)),
            Err(lua) => lua,
        };

        let lua = match LuaRead::lua_read_at_position(&lua, index) {
            Ok(v) => return Ok(AnyHashableLuaValue::LuaAnyString(v)),
            Err(lua) => lua,
        };

        if unsafe { ffi::lua_isnil(lua.as_lua().0, index) } {
            return Ok(AnyHashableLuaValue::LuaNil);
        }

        // let _lua = match LuaRead::lua_read_at_position(&lua, index) {
        // Ok(v) => return Ok(AnyHashableLuaValue::LuaArray(v)),
        // Err(lua) => lua
        // };

        Ok(AnyHashableLuaValue::LuaOther)
    }
}

#[cfg(test)]
mod tests {
    use Lua;
    use AnyLuaValue;
    use AnyHashableLuaValue;
    use AnyLuaString;

    #[test]
    fn read_numbers() {
        let mut lua = Lua::new();

        lua.set("a", "-2");
        lua.set("b", 3.5f32);

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaString("-2".to_owned()));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaNumber(3.5));
    }

    #[test]
    fn read_hashable_numbers() {
        let mut lua = Lua::new();

        lua.set("a", "-2");
        lua.set("b", "4");

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaNumber(-2));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaNumber(4));
    }

    #[test]
    fn read_strings() {
        let mut lua = Lua::new();

        lua.set("a", "hello");
        lua.set("b", "3x");
        lua.set("c", "false");

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaString("hello".to_string()));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaString("3x".to_string()));

        let z: AnyLuaValue = lua.get("c").unwrap();
        assert_eq!(z, AnyLuaValue::LuaString("false".to_string()));
    }

    #[test]
    fn read_hashable_strings() {
        let mut lua = Lua::new();

        lua.set("a", "hello");
        lua.set("b", "3x");
        lua.set("c", "false");

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaString("hello".to_string()));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaString("3x".to_string()));

        let z: AnyHashableLuaValue = lua.get("c").unwrap();
        assert_eq!(z, AnyHashableLuaValue::LuaString("false".to_string()));
    }

    #[test]
    fn read_booleans() {
        let mut lua = Lua::new();

        lua.set("a", true);
        lua.set("b", false);

        let x: AnyLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyLuaValue::LuaBoolean(true));

        let y: AnyLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyLuaValue::LuaBoolean(false));
    }

    #[test]
    fn read_hashable_booleans() {
        let mut lua = Lua::new();

        lua.set("a", true);
        lua.set("b", false);

        let x: AnyHashableLuaValue = lua.get("a").unwrap();
        assert_eq!(x, AnyHashableLuaValue::LuaBoolean(true));

        let y: AnyHashableLuaValue = lua.get("b").unwrap();
        assert_eq!(y, AnyHashableLuaValue::LuaBoolean(false));
    }

    #[test]
    fn push_numbers() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaNumber(3.0));

        let x: i32 = lua.get("a").unwrap();
        assert_eq!(x, 3);
    }

    #[test]
    fn push_hashable_numbers() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaNumber(3));

        let x: i32 = lua.get("a").unwrap();
        assert_eq!(x, 3);
    }

    #[test]
    fn push_strings() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaString("hello".to_string()));

        let x: String = lua.get("a").unwrap();
        assert_eq!(x, "hello");
    }

    #[test]
    fn push_hashable_strings() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaString("hello".to_string()));

        let x: String = lua.get("a").unwrap();
        assert_eq!(x, "hello");
    }

    #[test]
    fn push_booleans() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaBoolean(true));

        let x: bool = lua.get("a").unwrap();
        assert_eq!(x, true);
    }

    #[test]
    fn push_hashable_booleans() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaBoolean(true));

        let x: bool = lua.get("a").unwrap();
        assert_eq!(x, true);
    }

    #[test]
    fn push_nil() {
        let mut lua = Lua::new();

        lua.set("a", AnyLuaValue::LuaNil);

        let x: Option<i32> = lua.get("a");
        assert!(x.is_none(),
                "x is a Some value when it should be a None value. X: {:?}",
                x);
    }

    #[test]
    fn push_hashable_nil() {
        let mut lua = Lua::new();

        lua.set("a", AnyHashableLuaValue::LuaNil);

        let x: Option<i32> = lua.get("a");
        assert!(x.is_none(),
                "x is a Some value when it should be a None value. X: {:?}",
                x);
    }

    #[test]
    fn non_utf_8_string() {
        let mut lua = Lua::new();
        let a = lua.execute::<AnyLuaValue>(r"return '\xff\xfe\xff\xfe'").unwrap();
        match a {
            AnyLuaValue::LuaAnyString(AnyLuaString(v)) => {
                assert_eq!(Vec::from(&b"\xff\xfe\xff\xfe"[..]), v);
            },
            _ => panic!("Decoded to wrong variant"),
        }
    }
}
<|endoftext|>