<commit_before>use std::str::from_utf8;
use std::result::Result;
use nom::IResult;

/*
 * Core structs
 */

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific + sparse */
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparse:     [Sparse; 4],
    pub isextended: bool,
    pub realsize:   u64
}

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

/*
 * Useful macros
 */

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8) ~
            take!($size - s.len()),
            ||{
                s
            }
        )
    );
);

named!(parse_str4<&[u8], &str>, take_str_eat_garbage!(4));
named!(parse_str8<&[u8], &str>, take_str_eat_garbage!(8));
named!(parse_str32<&[u8], &str>, take_str_eat_garbage!(32));
named!(parse_str100<&[u8], &str>, take_str_eat_garbage!(100));
named!(parse_str155<&[u8], &str>, take_str_eat_garbage!(155));

/*
 * Octal string parsing
 */

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn parse_octal(i: &[u8], n: usize) -> IResult<&[u8], u64> {
    map_res!(i, take_str_eat_garbage!(n), octal_to_u64)
}

named!(parse_octal8<&[u8], u64>, apply!(parse_octal, 8));
named!(parse_octal12<&[u8], u64>, apply!(parse_octal, 12));

/*
 * TypeFlag parsing
 */

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn bytes_to_type_flag(i: &[u8]) -> Result<TypeFlag, &'static str> {
    Ok(char_to_type_flag(i[0] as char))
}

named!(parse_type_flag<&[u8], TypeFlag>, map_res!(take!(1), bytes_to_type_flag));

/*
 * Sparse parsing
 */

fn parse_one_sparse(i: &[u8]) -> IResult<&[u8], Sparse> {
    chain!(i,
        offset:   parse_octal12 ~
        numbytes: parse_octal12,
        ||{
            Sparse {
                offset:   offset,
                numbytes: numbytes
            }
        }
    )
}

fn parse_sparse(i: &[u8]) -> IResult<&[u8], [Sparse; 4]> {
    count!(i, parse_one_sparse, Sparse, 4)
}

/*
 * Boolean parsing
 */

fn to_bool(i: &[u8]) -> Result<bool, &'static str> {
    Ok(i[0] != 0)
}

named!(parse_bool<&[u8], bool>, map_res!(take!(1), to_bool));

/*
 * UStar PAX extended parsing
 */

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        atime:      parse_octal12 ~
        ctime:      parse_octal12 ~
        offset:     parse_octal12 ~
        longnames:  parse_str4    ~
        take!(1)                  ~
        sparse:     parse_sparse  ~
        isextended: parse_bool    ~
        realsize:   parse_octal12 ~
        take!(17), /* padding to 512 */
        ||{
            UStarExtraHeader::Pax(PaxHeader {
                atime:      atime,
                ctime:      ctime,
                offset:     offset,
                longnames:  longnames,
                sparse:     sparse,
                isextended: isextended,
                realsize:   realsize
            })
        }
    )
}

/*
 * UStar Posix parsing
 */

fn parse_ustar00_extra_posix(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        prefix: parse_str155 ~
        take!(12),
        ||{
            UStarExtraHeader::PosixUStar(PosixUStarHeader {
                prefix: prefix
            })
        }
    )
}

fn parse_ustar00_extra(i: &[u8], flag: TypeFlag) -> IResult<&[u8], UStarExtraHeader> {
    match flag {
        TypeFlag::PaxInterexchangeFormat => parse_ustar00_extra_pax(i),
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("00")             ~
        uname:    parse_str32  ~
        gname:    parse_str32  ~
        devmajor: parse_octal8 ~
        devminor: parse_octal8 ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

/*
 * Posix tar archive header parsing
 */

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     parse_str100    ~
        mode:     parse_str8      ~
        uid:      parse_octal8    ~
        gid:      parse_octal8    ~
        size:     parse_octal12   ~
        mtime:    parse_octal12   ~
        chksum:   parse_str8      ~
        typeflag: parse_type_flag ~
        linkname: parse_str100    ~
        ustar:    alt!(apply!(parse_ustar, typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

/*
 * Contents parsing
 */

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

/*
 * Tar entry header + contents parsing
 */

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

/*
 * Tar archive parsing
 */

fn filter_entries(entries: Vec<TarEntry>) -> Result<Vec<TarEntry>, &'static str> {
    /* Filter out empty entries */
    Ok(entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>())
}

// TODO: eof
pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    map_res!(i, many0!(parse_entry), filter_entries)
}

/*
 * Tests
 */

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<commit_msg>ensure eof<commit_after>use std::str::from_utf8;
use std::result::Result;
use nom::{IResult,eof};

/*
 * Core structs
 */

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific + sparse */
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparse:     [Sparse; 4],
    pub isextended: bool,
    pub realsize:   u64
}

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

/*
 * Useful macros
 */

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8) ~
            take!($size - s.len()),
            ||{
                s
            }
        )
    );
);

named!(parse_str4<&[u8], &str>, take_str_eat_garbage!(4));
named!(parse_str8<&[u8], &str>, take_str_eat_garbage!(8));
named!(parse_str32<&[u8], &str>, take_str_eat_garbage!(32));
named!(parse_str100<&[u8], &str>, take_str_eat_garbage!(100));
named!(parse_str155<&[u8], &str>, take_str_eat_garbage!(155));

/*
 * Octal string parsing
 */

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn parse_octal(i: &[u8], n: usize) -> IResult<&[u8], u64> {
    map_res!(i, take_str_eat_garbage!(n), octal_to_u64)
}

named!(parse_octal8<&[u8], u64>, apply!(parse_octal, 8));
named!(parse_octal12<&[u8], u64>, apply!(parse_octal, 12));

/*
 * TypeFlag parsing
 */

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn bytes_to_type_flag(i: &[u8]) -> Result<TypeFlag, &'static str> {
    Ok(char_to_type_flag(i[0] as char))
}

named!(parse_type_flag<&[u8], TypeFlag>, map_res!(take!(1), bytes_to_type_flag));

/*
 * Sparse parsing
 */

fn parse_one_sparse(i: &[u8]) -> IResult<&[u8], Sparse> {
    chain!(i,
        offset:   parse_octal12 ~
        numbytes: parse_octal12,
        ||{
            Sparse {
                offset:   offset,
                numbytes: numbytes
            }
        }
    )
}

fn parse_sparse(i: &[u8]) -> IResult<&[u8], [Sparse; 4]> {
    count!(i, parse_one_sparse, Sparse, 4)
}

/*
 * Boolean parsing
 */

fn to_bool(i: &[u8]) -> Result<bool, &'static str> {
    Ok(i[0] != 0)
}

named!(parse_bool<&[u8], bool>, map_res!(take!(1), to_bool));

/*
 * UStar PAX extended parsing
 */

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        atime:      parse_octal12 ~
        ctime:      parse_octal12 ~
        offset:     parse_octal12 ~
        longnames:  parse_str4    ~
        take!(1)                  ~
        sparse:     parse_sparse  ~
        isextended: parse_bool    ~
        realsize:   parse_octal12 ~
        take!(17), /* padding to 512 */
        ||{
            UStarExtraHeader::Pax(PaxHeader {
                atime:      atime,
                ctime:      ctime,
                offset:     offset,
                longnames:  longnames,
                sparse:     sparse,
                isextended: isextended,
                realsize:   realsize
            })
        }
    )
}

/*
 * UStar Posix parsing
 */

fn parse_ustar00_extra_posix(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        prefix: parse_str155 ~
        take!(12),
        ||{
            UStarExtraHeader::PosixUStar(PosixUStarHeader {
                prefix: prefix
            })
        }
    )
}

fn parse_ustar00_extra(i: &[u8], flag: TypeFlag) -> IResult<&[u8], UStarExtraHeader> {
    match flag {
        TypeFlag::PaxInterexchangeFormat => parse_ustar00_extra_pax(i),
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("00")             ~
        uname:    parse_str32  ~
        gname:    parse_str32  ~
        devmajor: parse_octal8 ~
        devminor: parse_octal8 ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

/*
 * Posix tar archive header parsing
 */

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     parse_str100    ~
        mode:     parse_str8      ~
        uid:      parse_octal8    ~
        gid:      parse_octal8    ~
        size:     parse_octal12   ~
        mtime:    parse_octal12   ~
        chksum:   parse_str8      ~
        typeflag: parse_type_flag ~
        linkname: parse_str100    ~
        ustar:    alt!(apply!(parse_ustar, typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

/*
 * Contents parsing
 */

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

/*
 * Tar entry header + contents parsing
 */

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

/*
 * Tar archive parsing
 */

fn filter_entries(entries: Vec<TarEntry>) -> Result<Vec<TarEntry>, &'static str> {
    /* Filter out empty entries */
    Ok(entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>())
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    chain!(i,
        entries: map_res!(many0!(parse_entry), filter_entries) ~
        eof,
        ||{
            entries
        }
    )
}

/*
 * Tests
 */

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<|endoftext|>


<commit_before>use std::any::Any;

use graphics;
use opengl_graphics::*;
use graphics_context::GraphicsContext;
use entity::Entity;
use config::TILE_WIDTH;
use config::TILE_HEIGHT;

use cgmath::Vector2;

use piston::input::*;

pub struct Player
{
    pos : Vector2<f64>,
    dir : Vector2<f64>,
    emotion: String,
    pressed : [bool;4]  // up, right, down, left
}

impl Player
{
    pub fn new(texture: String) -> Player {
        Player {
            pos: Vector2::<f64>::new(50.0f64, 50.0f64),
            dir: Vector2::<f64>::new(0.0f64, 0.0f64),
            emotion: texture,
            pressed : [false, false, false, false]
        }
    }
    pub fn key_release(&mut self, button: Button) {
        match button {
            Button::Keyboard(Key::W) => { self.pressed[0] = false },
            Button::Keyboard(Key::D) => { self.pressed[1] = false },
            Button::Keyboard(Key::S) => { self.pressed[2] = false },
            Button::Keyboard(Key::A) => { self.pressed[3] = false },
            _ => {}
        };
        self.update_movement_state();
    }

    pub fn key_press(&mut self, button: Button) {
        match button {
            Button::Keyboard(Key::W) => { self.pressed[0] = true },
            Button::Keyboard(Key::D) => { self.pressed[1] = true },
            Button::Keyboard(Key::S) => { self.pressed[2] = true },
            Button::Keyboard(Key::A) => { self.pressed[3] = true },
            _ => {}
        };
        self.update_movement_state();
    }

    fn update_movement_state(&mut self) {
        let mut x_mov = 0.0f64;
        let mut y_mov = 0.0f64;
        let speed = 1f64;
        if self.pressed[0] { y_mov -= speed; }
        if self.pressed[1] { x_mov += speed; }
        if self.pressed[2] { y_mov += speed; }
        if self.pressed[3] { x_mov -= speed; }
        self.dir.x = x_mov;
        self.dir.y = y_mov;
        /*if (x_mov != 0.0f64 || y_mov != 0.0f64) {
            auto position = entity.component<Position>();

            glm::vec2 direction(radius, angle);
            glm::vec2 velocity = float(dt) * glm::normalize(direction);
            velocity *= MAX_SPEED;

            // adjust angle speed to match "radial" speed via arc length
            if (position->position()[0] != 0) { // only adjust if radius != 0 ????
                velocity[1] /= position->position()[0];
            }

            velocity_e->m_accelerating = true;
            glm::vec2 d = velocity_e->m_desired_velocity - velocity;
            if(glm::length(d) > 0.01)
            {
              velocity_e->m_desired_velocity = velocity;
              velocity_e->m_start_velocity = velocity_e->m_velocity;
              velocity_e->m_alpha = 0.0f;
              velocity_e->m_alpha_step = ACCELERATION_STEP;
            }
        }*/
    }
}

impl Entity for Player {
    fn as_any(&mut self) -> &mut Any {
        self
    }

    fn update(&mut self, args: UpdateArgs) {
        self.pos.x += 100.0f64 * args.dt as f64 * self.dir.x;
        self.pos.y += 100.0f64 * args.dt as f64 * self.dir.y;
        println!("x:{} y:{}", self.pos.x, self.pos.y);
    }

    fn render(&mut self, ctx : &mut GraphicsContext, c: graphics::context::Context, gl: &mut GlGraphics) {
        ctx.draw_texture(c, gl, self.emotion.clone(), self.pos.x as u32, self.pos.y as u32, TILE_WIDTH, TILE_HEIGHT);
    }

    fn get_position(&self) -> Vector2<f64> {
        Vector2::<f64>::new(self.pos.x, self.pos.y)
    }
}
<commit_msg>Reduced verbosity.<commit_after>use std::any::Any;

use graphics;
use opengl_graphics::*;
use graphics_context::GraphicsContext;
use entity::Entity;
use config::TILE_WIDTH;
use config::TILE_HEIGHT;

use cgmath::Vector2;

use piston::input::*;

pub struct Player
{
    pos : Vector2<f64>,
    dir : Vector2<f64>,
    emotion: String,
    pressed : [bool;4]  // up, right, down, left
}

impl Player
{
    pub fn new(texture: String) -> Player {
        Player {
            pos: Vector2::<f64>::new(50.0f64, 50.0f64),
            dir: Vector2::<f64>::new(0.0f64, 0.0f64),
            emotion: texture,
            pressed : [false, false, false, false]
        }
    }
    pub fn key_release(&mut self, button: Button) {
        match button {
            Button::Keyboard(Key::W) => { self.pressed[0] = false },
            Button::Keyboard(Key::D) => { self.pressed[1] = false },
            Button::Keyboard(Key::S) => { self.pressed[2] = false },
            Button::Keyboard(Key::A) => { self.pressed[3] = false },
            _ => {}
        };
        self.update_movement_state();
    }

    pub fn key_press(&mut self, button: Button) {
        match button {
            Button::Keyboard(Key::W) => { self.pressed[0] = true },
            Button::Keyboard(Key::D) => { self.pressed[1] = true },
            Button::Keyboard(Key::S) => { self.pressed[2] = true },
            Button::Keyboard(Key::A) => { self.pressed[3] = true },
            _ => {}
        };
        self.update_movement_state();
    }

    fn update_movement_state(&mut self) {
        let mut x_mov = 0.0f64;
        let mut y_mov = 0.0f64;
        let speed = 1f64;
        if self.pressed[0] { y_mov -= speed; }
        if self.pressed[1] { x_mov += speed; }
        if self.pressed[2] { y_mov += speed; }
        if self.pressed[3] { x_mov -= speed; }
        self.dir.x = x_mov;
        self.dir.y = y_mov;
        /*if (x_mov != 0.0f64 || y_mov != 0.0f64) {
            auto position = entity.component<Position>();

            glm::vec2 direction(radius, angle);
            glm::vec2 velocity = float(dt) * glm::normalize(direction);
            velocity *= MAX_SPEED;

            // adjust angle speed to match "radial" speed via arc length
            if (position->position()[0] != 0) { // only adjust if radius != 0 ????
                velocity[1] /= position->position()[0];
            }

            velocity_e->m_accelerating = true;
            glm::vec2 d = velocity_e->m_desired_velocity - velocity;
            if(glm::length(d) > 0.01)
            {
              velocity_e->m_desired_velocity = velocity;
              velocity_e->m_start_velocity = velocity_e->m_velocity;
              velocity_e->m_alpha = 0.0f;
              velocity_e->m_alpha_step = ACCELERATION_STEP;
            }
        }*/
    }
}

impl Entity for Player {
    fn as_any(&mut self) -> &mut Any {
        self
    }

    fn update(&mut self, args: UpdateArgs) {
        self.pos.x += 100.0f64 * args.dt as f64 * self.dir.x;
        self.pos.y += 100.0f64 * args.dt as f64 * self.dir.y;
    }

    fn render(&mut self, ctx : &mut GraphicsContext, c: graphics::context::Context, gl: &mut GlGraphics) {
        ctx.draw_texture(c, gl, self.emotion.clone(), self.pos.x as u32, self.pos.y as u32, TILE_WIDTH, TILE_HEIGHT);
    }

    fn get_position(&self) -> Vector2<f64> {
        Vector2::<f64>::new(self.pos.x, self.pos.y)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate api_server;
extern crate libc;
#[macro_use]
extern crate logger;
extern crate mmds;
extern crate polly;
extern crate seccomp;
extern crate timerfd;
extern crate utils;
extern crate vmm;

mod api_server_adapter;
mod metrics;

use std::fs;
use std::io;
use std::panic;
use std::path::PathBuf;
use std::process;
use std::sync::{Arc, Mutex};

use logger::{Metric, LOGGER, METRICS};
use polly::event_manager::EventManager;
use seccomp::{BpfProgram, SeccompLevel};
use utils::arg_parser::{ArgParser, Argument};
use utils::terminal::Terminal;
use utils::validators::validate_instance_id;
use vmm::default_syscalls::get_seccomp_filter;
use vmm::resources::VmResources;
use vmm::signal_handler::register_signal_handlers;
use vmm::vmm_config::instance_info::InstanceInfo;
use vmm::vmm_config::logger::{init_logger, LoggerConfig, LoggerLevel};

// The reason we place default API socket under /run is that API socket is a
// runtime file.
// see https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s15.html for more information.
const DEFAULT_API_SOCK_PATH: &str = "/run/firecracker.socket";
const DEFAULT_INSTANCE_ID: &str = "anonymous-instance";
const FIRECRACKER_VERSION: &str = env!("CARGO_PKG_VERSION");

fn main() {
    LOGGER
        .configure(Some(DEFAULT_INSTANCE_ID.to_string()))
        .expect("Failed to register logger");

    if let Err(e) = register_signal_handlers() {
        error!("Failed to register signal handlers: {}", e);
        process::exit(i32::from(vmm::FC_EXIT_CODE_GENERIC_ERROR));
    }

    // We need this so that we can reset terminal to canonical mode if panic occurs.
    let stdin = io::stdin();

    // Start firecracker by setting up a panic hook, which will be called before
    // terminating as we're building with panic = "abort".
    // It's worth noting that the abort is caused by sending a SIG_ABORT signal to the process.
    panic::set_hook(Box::new(move |info| {
        // We're currently using the closure parameter, which is a &PanicInfo, for printing the
        // origin of the panic, including the payload passed to panic! and the source code location
        // from which the panic originated.
        error!("Firecracker {}", info);
        if let Err(e) = stdin.lock().set_canon_mode() {
            error!(
                "Failure while trying to reset stdin to canonical mode: {}",
                e
            );
        }

        METRICS.vmm.panic_count.inc();

        // Write the metrics before aborting.
        if let Err(e) = METRICS.write() {
            error!("Failed to write metrics while panicking: {}", e);
        }
    }));

    let mut arg_parser = ArgParser::new()
        .arg(
            Argument::new("api-sock")
                .takes_value(true)
                .default_value(DEFAULT_API_SOCK_PATH)
                .help("Path to unix domain socket used by the API."),
        )
        .arg(
            Argument::new("id")
                .takes_value(true)
                .default_value(DEFAULT_INSTANCE_ID)
                .help("MicroVM unique identifier."),
        )
        .arg(
            Argument::new("seccomp-level")
                .takes_value(true)
                .default_value("2")
                .help(
                    "Level of seccomp filtering (0: no filter | 1: filter by syscall number | 2: filter by syscall \
                     number and argument values) that will be passed to executed path as argument."
                ),
        )
        .arg(
            Argument::new("start-time-us")
                .takes_value(true)
                .help("Process start time (wall clock, microseconds)."),
        )
        .arg(
            Argument::new("start-time-cpu-us")
                .takes_value(true)
                .help("Process start CPU time (wall clock, microseconds)."),
        )
        .arg(
            Argument::new("config-file")
                .takes_value(true)
                .help("Path to a file that contains the microVM configuration in JSON format."),
        )
        .arg(
            Argument::new("no-api")
                .takes_value(false)
                .requires("config-file")
                .help("Optional parameter which allows starting and using a microVM without an active API socket.")
        )
        .arg(
            Argument::new("log-path")
                .takes_value(true)
                .help("Path to a fifo or a file used for configuring the logger on startup.")
        )
        .arg(
            Argument::new("level")
                .takes_value(true)
                .requires("log-path")
                .default_value("Warning")
                .help("Set the logger level.")
        )
        .arg(
            Argument::new("show-level")
                .takes_value(false)
                .requires("log-path")
                .help("Whether or not to output the level in the logs.")
        )
        .arg(
            Argument::new("show-log-origin")
                .takes_value(false)
                .requires("log-path")
                .help("Whether or not to include the file path and line number of the log's origin.")
        );

    let arguments = match arg_parser.parse_from_cmdline() {
        Err(err) => {
            error!(
                "Arguments parsing error: {} \n\n\
                 For more information try --help.",
                err
            );
            process::exit(i32::from(vmm::FC_EXIT_CODE_ARG_PARSING));
        }
        _ => {
            if let Some(help) = arg_parser.arguments().value_as_bool("help") {
                if help {
                    println!("Firecracker v{}\n", FIRECRACKER_VERSION);
                    println!("{}", arg_parser.formatted_help());
                    process::exit(i32::from(vmm::FC_EXIT_CODE_OK));
                }
            }

            if let Some(version) = arg_parser.arguments().value_as_bool("version") {
                if version {
                    println!("Firecracker v{}\n", FIRECRACKER_VERSION);
                    process::exit(i32::from(vmm::FC_EXIT_CODE_OK));
                }
            }

            arg_parser.arguments()
        }
    };

    // It's safe to unwrap here because the field's been provided with a default value.
    let instance_id = arguments.value_as_string("id").unwrap();
    validate_instance_id(instance_id.as_str()).expect("Invalid instance ID");

    let instance_info = InstanceInfo {
        id: instance_id.clone(),
        started: false,
        vmm_version: FIRECRACKER_VERSION.to_string(),
        app_name: "Firecracker".to_string(),
    };

    LOGGER.set_instance_id(instance_id);

    if let Some(log) = arguments.value_as_string("log-path") {
        // It's safe to unwrap here because the field's been provided with a default value.
        let level = arguments.value_as_string("level").unwrap();
        let logger_level = LoggerLevel::from_string(level).unwrap_or_else(|err| {
            panic!("Invalid value for logger level: {}. Possible values: [Error, Warning, Info, Debug]", err);
        });
        let show_level = arguments.value_as_bool("show-level").unwrap_or(false);
        let show_log_origin = arguments.value_as_bool("show-log-origin").unwrap_or(false);

        let logger_config = LoggerConfig::new(
            PathBuf::from(log),
            logger_level,
            show_level,
            show_log_origin,
        );
        init_logger(logger_config, &instance_info).expect("Could not initialize logger.");
    }

    // It's safe to unwrap here because the field's been provided with a default value.
    let seccomp_level = arguments.value_as_string("seccomp-level").unwrap();
    let seccomp_filter = get_seccomp_filter(
        SeccompLevel::from_string(seccomp_level).unwrap_or_else(|err| {
            panic!("Invalid value for seccomp-level: {}", err);
        }),
    )
    .unwrap_or_else(|err| {
        panic!("Could not create seccomp filter: {}", err);
    });

    let vmm_config_json = arguments
        .value_as_string("config-file")
        .map(fs::read_to_string)
        .map(|x| x.expect("Unable to open or read from the configuration file"));

    let api_enabled = !arguments.value_as_bool("no-api").unwrap_or(false);

    if api_enabled {
        let bind_path = arguments
            .value_as_string("api-sock")
            .map(PathBuf::from)
            .expect("Missing argument: api-sock");

        let start_time_us = arguments.value_as_string("start-time-us").map(|s| {
            s.parse::<u64>()
                .expect("'start-time-us' parameter expected to be of 'u64' type.")
        });

        let start_time_cpu_us = arguments.value_as_string("start-time-cpu-us").map(|s| {
            s.parse::<u64>()
                .expect("'start-time-cpu-us' parameter expected to be of 'u64' type.")
        });
        api_server_adapter::run_with_api(
            seccomp_filter,
            vmm_config_json,
            bind_path,
            instance_info,
            start_time_us,
            start_time_cpu_us,
        );
    } else {
        run_without_api(seccomp_filter, vmm_config_json, &instance_info);
    }
}

// Configure and start a microVM as described by the command-line JSON.
fn build_microvm_from_json(
    seccomp_filter: BpfProgram,
    event_manager: &mut EventManager,
    config_json: String,
    instance_info: &InstanceInfo,
) -> (VmResources, Arc<Mutex<vmm::Vmm>>) {
    let vm_resources = VmResources::from_json(&config_json, instance_info).unwrap_or_else(|err| {
        error!(
            "Configuration for VMM from one single json failed: {:?}",
            err
        );
        process::exit(i32::from(vmm::FC_EXIT_CODE_BAD_CONFIGURATION));
    });
    let vmm = vmm::builder::build_microvm_for_boot(&vm_resources, event_manager, &seccomp_filter)
        .unwrap_or_else(|err| {
            error!(
                "Building VMM configured from cmdline json failed: {:?}",
                err
            );
            process::exit(i32::from(vmm::FC_EXIT_CODE_BAD_CONFIGURATION));
        });
    info!("Successfully started microvm that was configured from one single json");

    (vm_resources, vmm)
}

fn run_without_api(
    seccomp_filter: BpfProgram,
    config_json: Option<String>,
    instance_info: &InstanceInfo,
) {
    let mut event_manager = EventManager::new().expect("Unable to create EventManager");

    // Create the firecracker metrics object responsible for periodically printing metrics.
    let firecracker_metrics = Arc::new(Mutex::new(metrics::PeriodicMetrics::new()));
    event_manager
        .add_subscriber(firecracker_metrics.clone())
        .expect("Cannot register the metrics event to the event manager.");

    // Build the microVm. We can ignore the returned values here because:
    // - VmResources is not used without api,
    // - An `Arc` reference of the built `Vmm` is plugged in the `EventManager` by the builder.
    build_microvm_from_json(
        seccomp_filter,
        &mut event_manager,
        // Safe to unwrap since '--no-api' requires this to be set.
        config_json.unwrap(),
        instance_info,
    );

    // Start the metrics.
    firecracker_metrics
        .lock()
        .expect("Poisoned lock")
        .start(metrics::WRITE_METRICS_PERIOD_MS);

    // Run the EventManager that drives everything in the microVM.
    loop {
        event_manager
            .run()
            .expect("Failed to start the event manager");
    }
}
<commit_msg>Gracefully handle cmd line logger errors<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate api_server;
extern crate libc;
#[macro_use]
extern crate logger;
extern crate mmds;
extern crate polly;
extern crate seccomp;
extern crate timerfd;
extern crate utils;
extern crate vmm;

mod api_server_adapter;
mod metrics;

use std::fs;
use std::io;
use std::panic;
use std::path::PathBuf;
use std::process;
use std::sync::{Arc, Mutex};

use logger::{Metric, LOGGER, METRICS};
use polly::event_manager::EventManager;
use seccomp::{BpfProgram, SeccompLevel};
use utils::arg_parser::{ArgParser, Argument};
use utils::terminal::Terminal;
use utils::validators::validate_instance_id;
use vmm::default_syscalls::get_seccomp_filter;
use vmm::resources::VmResources;
use vmm::signal_handler::register_signal_handlers;
use vmm::vmm_config::instance_info::InstanceInfo;
use vmm::vmm_config::logger::{init_logger, LoggerConfig, LoggerLevel};

// The reason we place default API socket under /run is that API socket is a
// runtime file.
// see https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s15.html for more information.
const DEFAULT_API_SOCK_PATH: &str = "/run/firecracker.socket";
const DEFAULT_INSTANCE_ID: &str = "anonymous-instance";
const FIRECRACKER_VERSION: &str = env!("CARGO_PKG_VERSION");

fn main() {
    LOGGER
        .configure(Some(DEFAULT_INSTANCE_ID.to_string()))
        .expect("Failed to register logger");

    if let Err(e) = register_signal_handlers() {
        error!("Failed to register signal handlers: {}", e);
        process::exit(i32::from(vmm::FC_EXIT_CODE_GENERIC_ERROR));
    }

    // We need this so that we can reset terminal to canonical mode if panic occurs.
    let stdin = io::stdin();

    // Start firecracker by setting up a panic hook, which will be called before
    // terminating as we're building with panic = "abort".
    // It's worth noting that the abort is caused by sending a SIG_ABORT signal to the process.
    panic::set_hook(Box::new(move |info| {
        // We're currently using the closure parameter, which is a &PanicInfo, for printing the
        // origin of the panic, including the payload passed to panic! and the source code location
        // from which the panic originated.
        error!("Firecracker {}", info);
        if let Err(e) = stdin.lock().set_canon_mode() {
            error!(
                "Failure while trying to reset stdin to canonical mode: {}",
                e
            );
        }

        METRICS.vmm.panic_count.inc();

        // Write the metrics before aborting.
        if let Err(e) = METRICS.write() {
            error!("Failed to write metrics while panicking: {}", e);
        }
    }));

    let mut arg_parser = ArgParser::new()
        .arg(
            Argument::new("api-sock")
                .takes_value(true)
                .default_value(DEFAULT_API_SOCK_PATH)
                .help("Path to unix domain socket used by the API."),
        )
        .arg(
            Argument::new("id")
                .takes_value(true)
                .default_value(DEFAULT_INSTANCE_ID)
                .help("MicroVM unique identifier."),
        )
        .arg(
            Argument::new("seccomp-level")
                .takes_value(true)
                .default_value("2")
                .help(
                    "Level of seccomp filtering (0: no filter | 1: filter by syscall number | 2: filter by syscall \
                     number and argument values) that will be passed to executed path as argument."
                ),
        )
        .arg(
            Argument::new("start-time-us")
                .takes_value(true)
                .help("Process start time (wall clock, microseconds)."),
        )
        .arg(
            Argument::new("start-time-cpu-us")
                .takes_value(true)
                .help("Process start CPU time (wall clock, microseconds)."),
        )
        .arg(
            Argument::new("config-file")
                .takes_value(true)
                .help("Path to a file that contains the microVM configuration in JSON format."),
        )
        .arg(
            Argument::new("no-api")
                .takes_value(false)
                .requires("config-file")
                .help("Optional parameter which allows starting and using a microVM without an active API socket.")
        )
        .arg(
            Argument::new("log-path")
                .takes_value(true)
                .help("Path to a fifo or a file used for configuring the logger on startup.")
        )
        .arg(
            Argument::new("level")
                .takes_value(true)
                .requires("log-path")
                .default_value("Warning")
                .help("Set the logger level.")
        )
        .arg(
            Argument::new("show-level")
                .takes_value(false)
                .requires("log-path")
                .help("Whether or not to output the level in the logs.")
        )
        .arg(
            Argument::new("show-log-origin")
                .takes_value(false)
                .requires("log-path")
                .help("Whether or not to include the file path and line number of the log's origin.")
        );

    let arguments = match arg_parser.parse_from_cmdline() {
        Err(err) => {
            error!(
                "Arguments parsing error: {} \n\n\
                 For more information try --help.",
                err
            );
            process::exit(i32::from(vmm::FC_EXIT_CODE_ARG_PARSING));
        }
        _ => {
            if let Some(help) = arg_parser.arguments().value_as_bool("help") {
                if help {
                    println!("Firecracker v{}\n", FIRECRACKER_VERSION);
                    println!("{}", arg_parser.formatted_help());
                    process::exit(i32::from(vmm::FC_EXIT_CODE_OK));
                }
            }

            if let Some(version) = arg_parser.arguments().value_as_bool("version") {
                if version {
                    println!("Firecracker v{}\n", FIRECRACKER_VERSION);
                    process::exit(i32::from(vmm::FC_EXIT_CODE_OK));
                }
            }

            arg_parser.arguments()
        }
    };

    // It's safe to unwrap here because the field's been provided with a default value.
    let instance_id = arguments.value_as_string("id").unwrap();
    validate_instance_id(instance_id.as_str()).expect("Invalid instance ID");

    let instance_info = InstanceInfo {
        id: instance_id.clone(),
        started: false,
        vmm_version: FIRECRACKER_VERSION.to_string(),
        app_name: "Firecracker".to_string(),
    };

    LOGGER.set_instance_id(instance_id);

    if let Some(log) = arguments.value_as_string("log-path") {
        // It's safe to unwrap here because the field's been provided with a default value.
        let level = arguments.value_as_string("level").unwrap();
        let logger_level = LoggerLevel::from_string(level).unwrap_or_else(|err| {
            error!("Invalid value for logger level: {}. Possible values: [Error, Warning, Info, Debug]", err);
            process::exit(i32::from(vmm::FC_EXIT_CODE_GENERIC_ERROR));
        });
        let show_level = arguments.value_as_bool("show-level").unwrap_or(false);
        let show_log_origin = arguments.value_as_bool("show-log-origin").unwrap_or(false);

        let logger_config = LoggerConfig::new(
            PathBuf::from(log),
            logger_level,
            show_level,
            show_log_origin,
        );
        init_logger(logger_config, &instance_info).unwrap_or_else(|err| {
            error!("Could not initialize logger: {}", err);
            process::exit(i32::from(vmm::FC_EXIT_CODE_GENERIC_ERROR));
        });
    }

    // It's safe to unwrap here because the field's been provided with a default value.
    let seccomp_level = arguments.value_as_string("seccomp-level").unwrap();
    let seccomp_filter = get_seccomp_filter(
        SeccompLevel::from_string(seccomp_level).unwrap_or_else(|err| {
            panic!("Invalid value for seccomp-level: {}", err);
        }),
    )
    .unwrap_or_else(|err| {
        panic!("Could not create seccomp filter: {}", err);
    });

    let vmm_config_json = arguments
        .value_as_string("config-file")
        .map(fs::read_to_string)
        .map(|x| x.expect("Unable to open or read from the configuration file"));

    let api_enabled = !arguments.value_as_bool("no-api").unwrap_or(false);

    if api_enabled {
        let bind_path = arguments
            .value_as_string("api-sock")
            .map(PathBuf::from)
            .expect("Missing argument: api-sock");

        let start_time_us = arguments.value_as_string("start-time-us").map(|s| {
            s.parse::<u64>()
                .expect("'start-time-us' parameter expected to be of 'u64' type.")
        });

        let start_time_cpu_us = arguments.value_as_string("start-time-cpu-us").map(|s| {
            s.parse::<u64>()
                .expect("'start-time-cpu-us' parameter expected to be of 'u64' type.")
        });
        api_server_adapter::run_with_api(
            seccomp_filter,
            vmm_config_json,
            bind_path,
            instance_info,
            start_time_us,
            start_time_cpu_us,
        );
    } else {
        run_without_api(seccomp_filter, vmm_config_json, &instance_info);
    }
}

// Configure and start a microVM as described by the command-line JSON.
fn build_microvm_from_json(
    seccomp_filter: BpfProgram,
    event_manager: &mut EventManager,
    config_json: String,
    instance_info: &InstanceInfo,
) -> (VmResources, Arc<Mutex<vmm::Vmm>>) {
    let vm_resources = VmResources::from_json(&config_json, instance_info).unwrap_or_else(|err| {
        error!(
            "Configuration for VMM from one single json failed: {:?}",
            err
        );
        process::exit(i32::from(vmm::FC_EXIT_CODE_BAD_CONFIGURATION));
    });
    let vmm = vmm::builder::build_microvm_for_boot(&vm_resources, event_manager, &seccomp_filter)
        .unwrap_or_else(|err| {
            error!(
                "Building VMM configured from cmdline json failed: {:?}",
                err
            );
            process::exit(i32::from(vmm::FC_EXIT_CODE_BAD_CONFIGURATION));
        });
    info!("Successfully started microvm that was configured from one single json");

    (vm_resources, vmm)
}

fn run_without_api(
    seccomp_filter: BpfProgram,
    config_json: Option<String>,
    instance_info: &InstanceInfo,
) {
    let mut event_manager = EventManager::new().expect("Unable to create EventManager");

    // Create the firecracker metrics object responsible for periodically printing metrics.
    let firecracker_metrics = Arc::new(Mutex::new(metrics::PeriodicMetrics::new()));
    event_manager
        .add_subscriber(firecracker_metrics.clone())
        .expect("Cannot register the metrics event to the event manager.");

    // Build the microVm. We can ignore the returned values here because:
    // - VmResources is not used without api,
    // - An `Arc` reference of the built `Vmm` is plugged in the `EventManager` by the builder.
    build_microvm_from_json(
        seccomp_filter,
        &mut event_manager,
        // Safe to unwrap since '--no-api' requires this to be set.
        config_json.unwrap(),
        instance_info,
    );

    // Start the metrics.
    firecracker_metrics
        .lock()
        .expect("Poisoned lock")
        .start(metrics::WRITE_METRICS_PERIOD_MS);

    // Run the EventManager that drives everything in the microVM.
    loop {
        event_manager
            .run()
            .expect("Failed to start the event manager");
    }
}
<|endoftext|>


<commit_before>//! Generation of semi-legal moves.
//! These are moves which, unlike those in [basic_moves], consider the positions
//! of other pieces. These move generation functions do not consider check or checkmate.

use board::square::Square;
use board::piece::Piece;
use board::player::Player;
use board::rank::Rank;
use board::file::File;
use board::bitboard::BitBoard;
use game::basic_moves;
use std::num::Wrapping;

/// Returns the moves a given pawn can make.
pub fn pawn_moves(square: Square, player: Player, blockers: BitBoard) -> BitBoard {
    let double_blockers = match player {
        Player::White => blockers | blockers << 8,
        Player::Black => blockers | blockers >> 8
    };
    basic_moves::pawn_moves(square, player) & !double_blockers
}

/// Returns the attacks a given pawn can make.
pub fn pawn_attacks(square: Square, player: Player, opponent_pieces: BitBoard) -> BitBoard {
    basic_moves::pawn_attacks(square, player) & opponent_pieces
}

// -----------------------------------
/// Returns the moves a given knight can make.
pub fn knight_moves(square: Square, blockers: BitBoard) -> BitBoard {
    basic_moves::knight(square) & !blockers
}

/// Returns the attacks a given knight can make.
pub fn knight_attacks(square: Square, opponent_pieces: BitBoard) -> BitBoard {
    basic_moves::knight(square) & opponent_pieces
}

// -----------------------------------
/// Returns the combination of moves and captures a rook can make, assuming the blockers
/// can all be captured.
fn rook_all_moves(square: Square, blockers: BitBoard) -> BitBoard {
    // gets the moves in the upward direction only
    fn rook_forward_moves(square: Square, blockers: BitBoard) -> BitBoard {
        let file_mask = square.file().to_bitboard();
        let pot_blockers = blockers & file_mask;

        let difference = pot_blockers - BitBoard::new((Wrapping(square.to_bitboard().to_u64()) * Wrapping(2)).0);
        let changed = difference ^ blockers;
        changed & file_mask
    }

    let up = rook_forward_moves(
        square,
        blockers);
    let down = rook_forward_moves(
        square.mirror_horizontal(),
        blockers.mirror_horizontal()).mirror_horizontal();
    let left = rook_forward_moves(
        square.mirror_diag(),
        blockers.mirror_diag()).mirror_diag();
    let right = rook_forward_moves(
        square.mirror_diag().mirror_horizontal(),
        blockers.mirror_diag().mirror_horizontal()).mirror_horizontal().mirror_diag();

    up | down | left | right
}

/// Returns the moves a given rook can make
pub fn rook_moves(square: Square, blockers: BitBoard) -> BitBoard {
    rook_all_moves(square, blockers) & !blockers
}

/// Returns the attacks a given rook can make
pub fn rook_attacks(square: Square, own_pieces: BitBoard, opponent_pieces: BitBoard) -> BitBoard {
    rook_all_moves(square, own_pieces | opponent_pieces) & opponent_pieces
}

// -----------------------------------
<commit_msg>Add king semilegal moves<commit_after>//! Generation of semi-legal moves.
//! These are moves which, unlike those in [basic_moves], consider the positions
//! of other pieces. These move generation functions do not consider check or checkmate.

use board::square::Square;
use board::piece::Piece;
use board::player::Player;
use board::rank::Rank;
use board::file::File;
use board::bitboard::BitBoard;
use game::basic_moves;
use std::num::Wrapping;

/// Returns the moves a given pawn can make.
pub fn pawn_moves(square: Square, player: Player, blockers: BitBoard) -> BitBoard {
    let double_blockers = match player {
        Player::White => blockers | blockers << 8,
        Player::Black => blockers | blockers >> 8
    };
    basic_moves::pawn_moves(square, player) & !double_blockers
}

/// Returns the attacks a given pawn can make.
pub fn pawn_attacks(square: Square, player: Player, opponent_pieces: BitBoard) -> BitBoard {
    basic_moves::pawn_attacks(square, player) & opponent_pieces
}

// -----------------------------------
/// Returns the moves a given knight can make.
pub fn knight_moves(square: Square, blockers: BitBoard) -> BitBoard {
    basic_moves::knight(square) & !blockers
}

/// Returns the attacks a given knight can make.
pub fn knight_attacks(square: Square, opponent_pieces: BitBoard) -> BitBoard {
    basic_moves::knight(square) & opponent_pieces
}

// -----------------------------------
/// Returns the moves a given king can make.
pub fn king_moves(square: Square, blockers: BitBoard) -> BitBoard {
    basic_moves::king(square) & !blockers
}

/// Returns the attacks a given king can make.
pub fn king_attacks(square: Square, opponent_pieces: BitBoard) -> BitBoard {
    basic_moves::king(square) & opponent_pieces
}

// -----------------------------------
/// Returns the combination of moves and captures a rook can make, assuming the blockers
/// can all be captured.
fn rook_all_moves(square: Square, blockers: BitBoard) -> BitBoard {
    // gets the moves in the upward direction only
    fn rook_forward_moves(square: Square, blockers: BitBoard) -> BitBoard {
        let file_mask = square.file().to_bitboard();
        let pot_blockers = blockers & file_mask;

        let difference = pot_blockers - BitBoard::new((Wrapping(square.to_bitboard().to_u64()) * Wrapping(2)).0);
        let changed = difference ^ blockers;
        changed & file_mask
    }

    let up = rook_forward_moves(
        square,
        blockers);
    let down = rook_forward_moves(
        square.mirror_horizontal(),
        blockers.mirror_horizontal()).mirror_horizontal();
    let left = rook_forward_moves(
        square.mirror_diag(),
        blockers.mirror_diag()).mirror_diag();
    let right = rook_forward_moves(
        square.mirror_diag().mirror_horizontal(),
        blockers.mirror_diag().mirror_horizontal()).mirror_horizontal().mirror_diag();

    up | down | left | right
}

/// Returns the moves a given rook can make
pub fn rook_moves(square: Square, blockers: BitBoard) -> BitBoard {
    rook_all_moves(square, blockers) & !blockers
}

/// Returns the attacks a given rook can make
pub fn rook_attacks(square: Square, own_pieces: BitBoard, opponent_pieces: BitBoard) -> BitBoard {
    rook_all_moves(square, own_pieces | opponent_pieces) & opponent_pieces
}

// -----------------------------------
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! deb {
  ( $e:expr ) => { println!(concat!("\x1b[36m    > ", $e, "\x1b[0m")); };
  ( $e:expr, $($arg:tt)* ) => { println!(concat!("\x1b[36m    > ", $e, "\x1b[0m"), $($arg)*); };
}

#[macro_export]
macro_rules! info {
  ( $e:expr ) => { println!(concat!("\x1b[34m    > ", $e, "\x1b[0m")); };
  ( $e:expr, $($arg:tt)* ) => { println!(concat!("\x1b[34m    > ", $e, "\x1b[0m"), $($arg)*); };
}

#[macro_export]
macro_rules! warn {
  ( $e:expr ) => { println!(concat!("\x1b[33m/!\\ > ", $e, "\x1b[0m")); };
  ( $e:expr, $($arg:tt)* ) => { println!(concat!("\x1b[33m/!\\ > ", $e, "\x1b[0m"), $($arg)*); };
}

#[macro_export]
macro_rules! err {
  ( $e:expr ) => { println!(concat!("\x1b[1;31m/!\\ > ", $e, "\x1b[0;0m")); };
  ( $e:expr, $($arg:tt)* ) => { println!(concat!("\x1b[1;31m/!\\ > ", $e, "\x1b[0;0m"), $($arg)*); };
}
<commit_msg>Changed how report.rs reports stuff.<commit_after>#[macro_export]
macro_rules! deb {
  ( $e:expr ) => { println!(concat!("\x1b[90m{} \x1b[36m> ", $e, "\x1b[0m"), ::time::now().ctime()); };
  ( $e:expr, $($arg:tt)+ ) => { println!(concat!("\x1b[90m{} \x1b[36m> ", $e, "\x1b[0m"), ::time::now().ctime(), $($arg)+); };
}

#[macro_export]
macro_rules! info {
  ( $e:expr ) => { println!(concat!("\x1b[90m{} \x1b[34m> ", $e, "\x1b[0m"), ::time::now().ctime()); };
  ( $e:expr, $($arg:tt)+ ) => { println!(concat!("\x1b[90m{} \x1b[34m> ", $e, "\x1b[0m"), ::time::now().ctime(), $($arg)+); };
}

#[macro_export]
macro_rules! warn {
  ( $e:expr ) => { println!(concat!("\x1b[90m{} \x1b[33m> ", $e, "\x1b[0m"), ::time::now().ctime()); };
  ( $e:expr, $($arg:tt)+ ) => { println!(concat!("\x1b[90m{} \x1b[33m> ", $e, "\x1b[0m"), ::time::now().ctime(), $($arg)+); };
}

#[macro_export]
macro_rules! err {
  ( $e:expr ) => { println!(concat!("\x1b[90m{} \x1b[1;31m> ", $e, "\x1b[0;0m"), ::time::now().ctime()); };
  ( $e:expr, $($arg:tt)+ ) => { println!(concat!("\x1b[90m{} \x1b[1;31m> ", $e, "\x1b[0;0m"), ::time::now().ctime(), $($arg)+); };
}
<|endoftext|>


<commit_before>extern crate errno;
extern crate libc;

use errno::errno;
use errno::Errno;

#[derive(Debug)]
pub enum ShellError {
    Code(u8),
    Signaled(i32),
    OtherError(::std::io::Error),
    Errno(&'static str, Errno),
}

impl ::std::convert::From<::std::io::Error> for ShellError {
    fn from(error: ::std::io::Error) -> ShellError {
        ShellError::OtherError(error)
    }
}
pub type ShellResult = ::std::result::Result<(), ShellError>;

pub fn check_errno(name: &'static str,
               result: libc::c_int) -> Result<libc::c_int, ShellError> {
    if result != -1 {
        Ok(result)
    } else {
        Err(ShellError::Errno(name, errno()))
    }
}

pub trait ShellResultExt {
    fn code(&self) -> u8;
    fn print_error(self);
}

impl <T> ShellResultExt for ::std::result::Result<T, ShellError> {
    fn code(&self) -> u8 {
        match self {
            &Ok(_) => 0,
            &Err(ShellError::Code(code)) => code,
            &Err(_) => 1
        }
    }

    fn print_error(self) {
        match self {
            Ok(_) => return,
            Err(err) => { eprintln!("{:?}", err); }
        }
    }
}
<commit_msg>Add var error<commit_after>extern crate errno;
extern crate libc;

use errno::Errno;
use errno::errno;
use std::convert::From;
use std::env;
use std::io;

#[derive(Debug)]
pub enum ShellError {
    Code(u8),
    Signaled(i32),
    IoError(io::Error),
    VarError(env::VarError),
    Errno(&'static str, Errno),
}

impl From<io::Error> for ShellError {
    fn from(error: io::Error) -> ShellError {
        ShellError::IoError(error)
    }
}

impl From<env::VarError> for ShellError {
    fn from(error: env::VarError) -> ShellError {
        ShellError::VarError(error)
    }
}

pub type ShellResult = ::std::result::Result<(), ShellError>;

pub fn check_errno(name: &'static str,
               result: libc::c_int) -> Result<libc::c_int, ShellError> {
    if result != -1 {
        Ok(result)
    } else {
        Err(ShellError::Errno(name, errno()))
    }
}

pub trait ShellResultExt {
    fn code(&self) -> u8;
    fn print_error(self);
}

impl <T> ShellResultExt for ::std::result::Result<T, ShellError> {
    fn code(&self) -> u8 {
        match self {
            &Ok(_) => 0,
            &Err(ShellError::Code(code)) => code,
            &Err(_) => 1
        }
    }

    fn print_error(self) {
        match self {
            Ok(_) => return,
            Err(err) => { eprintln!("{:?}", err); }
        }
    }
}
<|endoftext|>


<commit_before>use std::process;

#[must_use]
#[derive(Debug)]
pub enum ExitStatus {
    Ok,
    Warning,
    Critical,
    Unknown
}

impl ExitStatus {
    #![cfg_attr(test, allow(dead_code))]
    pub fn exit(self) -> ! {
        use self::ExitStatus::*;
        match self {
            Ok => process::exit(0),
            Warning => process::exit(1),
            Critical => process::exit(2),
            Unknown => process::exit(3)
        }
    }

    pub fn from_str(s: &str) -> ExitStatus {
        use ExitStatus::*;
        match s {
            "ok" => Ok,
            "warning" => Warning,
            "critical" => Critical,
            "unknown" => Unknown,
            _ => panic!("Unexpected exit status: {}", s)
        }
    }

    pub fn str_values() -> [&'static str; 4] {
        ["ok", "warn", "critical", "unknown"]
    }
}
<commit_msg>Add comparison to turbine-plugins::ExitStatus<commit_after>use std::process;
use std::cmp::{Ord};

#[must_use]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ExitStatus {
    Unknown,
    Ok,
    Warning,
    Critical,
}

impl ExitStatus {
    #![cfg_attr(test, allow(dead_code))]
    pub fn exit(self) -> ! {
        use self::ExitStatus::*;
        match self {
            Ok => process::exit(0),
            Warning => process::exit(1),
            Critical => process::exit(2),
            Unknown => process::exit(3)
        }
    }

    pub fn from_str(s: &str) -> ExitStatus {
        use ExitStatus::*;
        match s {
            "ok" => Ok,
            "warning" => Warning,
            "critical" => Critical,
            "unknown" => Unknown,
            _ => panic!("Unexpected exit status: {}", s)
        }
    }

    pub fn str_values() -> [&'static str; 4] {
        ["ok", "warn", "critical", "unknown"]
    }
}

#[test]
fn comparison_is_as_expected() {
    use ExitStatus::*;
    assert!(Ok < Critical);
    assert!(Ok < Warning);
    assert_eq!(std::cmp::max(Warning, Critical), Critical)
}
<|endoftext|>


<commit_before>extern crate clock_ticks;

use std::thread;
use std::cmp;
use std::io::Error;
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::HashMap;
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use super::{Config, Connection, ConnectionID, Handler};

/// Implementation of a multi-client server implementation with handler based
/// event dispatching.
pub struct Server {
    closed: bool,
    config: Config,
    address: Option<SocketAddr>
}

impl Server {

    /// Creates a new server with the given configuration.
    pub fn new(config: Config) -> Server {
        Server {
            closed: false,
            config: config,
            address: None
        }
    }

    /// Returns the local address the server is currently bound to.
    pub fn local_addr(&self) -> Option<SocketAddr> {
        self.address
    }

    /// Binds the server to the specified local address by creating a socket
    /// and actively listens for incoming client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind<T: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Server>, address: T
    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            address,
            self.config.packet_max_size
        ));

        self.bind_to_socket(handler, socket)

    }

    /// Binds the server to specified socket and actively listens for incoming
    /// client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind_to_socket<T: Socket>(
        &mut self, handler: &mut Handler<Server>, mut socket: T
    ) -> Result<(), Error> {

        // Extract bound address
        self.address = Some(try!(socket.local_addr()));

        // Extract packet reader
        let reader = socket.reader().unwrap();

        // Create connection management collections
        let mut dropped: Vec<ConnectionID> = Vec::new();
        let mut addresses: HashMap<ConnectionID, SocketAddr> = HashMap::new();
        let mut connections: HashMap<ConnectionID, Connection> = HashMap::new();

        // Invoke handler
        handler.bind(self);

        // Receive and send until we shut down.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();

            // Receive all incoming UDP packets to our local address
            while let Ok((addr, packet)) = reader.try_recv() {

                // Try to extract the connection id from the packet
                match Connection::id_from_packet(&self.config, &packet) {
                    Some(id) => {

                        if !connections.contains_key(&id) {

                            // In case of a unknown ConnectionID we create a
                            // new connection and map it to the id
                            let conn = Connection::new(
                                self.config,
                                addr,
                                handler.rate_limiter(&self.config)
                            );

                            connections.insert(id, conn);

                            // We also map the initial peer address to the id.
                            // this is done in order to reliable track the
                            // connection in case of address re-assignments by
                            // network address translation.
                            addresses.insert(id, addr);

                        }

                        // Check for changes in the peer address and update
                        // the address to ID mapping
                        let connection = connections.get_mut(&id).unwrap();
                        if addr != connection.peer_addr() {
                            connection.set_peer_addr(addr);
                            addresses.remove(&id).unwrap();
                            addresses.insert(id, addr);
                        }

                        // Then feed the packet into the connection object for
                        // parsing
                        connection.receive_packet(packet, self, handler);

                    },
                    None => { /* Ignore any invalid packets */ }
                }

            }

            // Invoke handler
            handler.tick_connections(self, &mut connections);

            // Create outgoing packets for all connections
            for (id, conn) in connections.iter_mut() {

                // Resolve the last known remote address for this
                // connection and send the data
                let addr = addresses.get(id).unwrap();

                // Then invoke the connection to send a outgoing packet
                conn.send_packet(&mut socket, addr, self, handler);

                // Collect all lost / closed connections
                if conn.open() == false {
                    dropped.push(*id);
                }

            }

            // Remove any dropped connections and their address mappings
            if dropped.is_empty() == false {

                for id in dropped.iter() {
                    connections.remove(id).unwrap().reset();
                    addresses.remove(id).unwrap();
                }

                dropped.clear();

            }

            // Calculate spend time in current loop iteration and limit ticks
            // accordingly
            let spend = (clock_ticks::precise_time_ns() - begin) / 1000000 ;
            thread::sleep_ms(
                cmp::max(1000 / self.config.send_rate - spend as u32, 0)
            );

        }

        // Invoke handler
        handler.shutdown(self);
        self.address = None;

        // Reset all connection states
        for (_, conn) in connections.iter_mut() {
            conn.reset();
        }

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Shuts down the server, closing all active connections.
    pub fn shutdown(&mut self) {
        self.closed = true;
    }

}

#[cfg(test)]
mod tests {

    extern crate clock_ticks;

    use std::thread;
    use std::collections::HashMap;
    use super::super::{Connection, ConnectionID, Config, Handler, Server};

    struct MockServerHandler {
        pub last_tick_time: u32,
        pub tick_count: u32,
        pub accumulated: u32
    }

    impl Handler<Server> for MockServerHandler {

        fn bind(&mut self, _: &mut Server) {
            self.last_tick_time = precise_time_ms();
        }

        fn tick_connections(
            &mut self, server: &mut Server,
            _: &mut HashMap<ConnectionID, Connection>
        ) {

            // Accumulate time so we can check that the artifical delay
            // was correct for by the servers tick loop
            if self.tick_count > 1 {
                self.accumulated += precise_time_ms() - self.last_tick_time;
            }

            self.last_tick_time = precise_time_ms();
            self.tick_count += 1;

            if self.tick_count == 5 {
                server.shutdown();
            }

            // Fake some load inside of the tick handler
            thread::sleep_ms(75);

        }

    }

    fn precise_time_ms() -> u32 {
        (clock_ticks::precise_time_ns() / 1000000) as u32
    }

    #[test]
    fn test_server_tick_delay() {

        let config = Config {
            send_rate: 10,
            .. Config::default()
        };

        let mut handler = MockServerHandler {
            last_tick_time: 0,
            tick_count: 0,
            accumulated: 0
        };

        let mut server = Server::new(config);
        server.bind(&mut handler, "127.0.0.1:0").unwrap();

        assert!(handler.accumulated <= 350);

    }

}

<commit_msg>Add tests for server connection handling<commit_after>extern crate clock_ticks;

use std::thread;
use std::cmp;
use std::io::Error;
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::HashMap;
use traits::socket::Socket;
use shared::udp_socket::UdpSocket;
use super::{Config, Connection, ConnectionID, Handler};

/// Implementation of a multi-client server implementation with handler based
/// event dispatching.
pub struct Server {
    closed: bool,
    config: Config,
    address: Option<SocketAddr>
}

impl Server {

    /// Creates a new server with the given configuration.
    pub fn new(config: Config) -> Server {
        Server {
            closed: false,
            config: config,
            address: None
        }
    }

    /// Returns the local address the server is currently bound to.
    pub fn local_addr(&self) -> Option<SocketAddr> {
        self.address
    }

    /// Binds the server to the specified local address by creating a socket
    /// and actively listens for incoming client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind<T: ToSocketAddrs>(
        &mut self, handler: &mut Handler<Server>, address: T
    ) -> Result<(), Error> {

        let socket = try!(UdpSocket::new(
            address,
            self.config.packet_max_size
        ));

        self.bind_to_socket(handler, socket)

    }

    /// Binds the server to specified socket and actively listens for incoming
    /// client connections.
    ///
    /// Clients connecting to the server must use a compatible connection
    /// / packet configuration in order to be able to connect.
    ///
    /// The `handler` is a struct that implements the `Handler` trait in order
    /// to handle events from the server and its connections.
    pub fn bind_to_socket<T: Socket>(
        &mut self, handler: &mut Handler<Server>, mut socket: T
    ) -> Result<(), Error> {

        // Extract bound address
        self.address = Some(try!(socket.local_addr()));

        // Extract packet reader
        let reader = socket.reader().unwrap();

        // Create connection management collections
        let mut dropped: Vec<ConnectionID> = Vec::new();
        let mut addresses: HashMap<ConnectionID, SocketAddr> = HashMap::new();
        let mut connections: HashMap<ConnectionID, Connection> = HashMap::new();

        // Invoke handler
        handler.bind(self);

        // Receive and send until we shut down.
        while !self.closed {

            // Get current time to correct tick delay in order to achieve
            // a more stable tick rate
            let begin = clock_ticks::precise_time_ns();

            // Receive all incoming UDP packets to our local address
            while let Ok((addr, packet)) = reader.try_recv() {

                // Try to extract the connection id from the packet
                match Connection::id_from_packet(&self.config, &packet) {
                    Some(id) => {

                        if !connections.contains_key(&id) {

                            // In case of a unknown ConnectionID we create a
                            // new connection and map it to the id
                            let conn = Connection::new(
                                self.config,
                                addr,
                                handler.rate_limiter(&self.config)
                            );

                            connections.insert(id, conn);

                            // We also map the initial peer address to the id.
                            // this is done in order to reliable track the
                            // connection in case of address re-assignments by
                            // network address translation.
                            addresses.insert(id, addr);

                        }

                        // Check for changes in the peer address and update
                        // the address to ID mapping
                        let connection = connections.get_mut(&id).unwrap();
                        if addr != connection.peer_addr() {
                            connection.set_peer_addr(addr);
                            addresses.remove(&id).unwrap();
                            addresses.insert(id, addr);
                        }

                        // Then feed the packet into the connection object for
                        // parsing
                        connection.receive_packet(packet, self, handler);

                    },
                    None => { /* Ignore any invalid packets */ }
                }

            }

            // Invoke handler
            handler.tick_connections(self, &mut connections);

            // Create outgoing packets for all connections
            for (id, conn) in connections.iter_mut() {

                // Resolve the last known remote address for this
                // connection and send the data
                let addr = addresses.get(id).unwrap();

                // Then invoke the connection to send a outgoing packet
                conn.send_packet(&mut socket, addr, self, handler);

                // Collect all lost / closed connections
                if conn.open() == false {
                    dropped.push(*id);
                }

            }

            // Remove any dropped connections and their address mappings
            if dropped.is_empty() == false {

                for id in dropped.iter() {
                    connections.remove(id).unwrap().reset();
                    addresses.remove(id).unwrap();
                }

                dropped.clear();

            }

            // Calculate spend time in current loop iteration and limit ticks
            // accordingly
            let spend = (clock_ticks::precise_time_ns() - begin) / 1000000 ;
            thread::sleep_ms(
                cmp::max(1000 / self.config.send_rate - spend as u32, 0)
            );

        }

        // Invoke handler
        handler.shutdown(self);
        self.address = None;

        // Reset all connection states
        for (_, conn) in connections.iter_mut() {
            conn.reset();
        }

        // Close the UDP socket
        socket.shutdown();

        Ok(())

    }

    /// Shuts down the server, closing all active connections.
    pub fn shutdown(&mut self) {
        self.closed = true;
    }

}

#[cfg(test)]
mod tests {

    extern crate clock_ticks;

    use std::net;
    use std::thread;
    use std::io::Error;
    use std::collections::HashMap;
    use std::sync::mpsc::{channel, Receiver};
    use super::super::{
        Connection, ConnectionID, Config, Handler, Server, Socket
    };

    fn precise_time_ms() -> u32 {
        (clock_ticks::precise_time_ns() / 1000000) as u32
    }

    struct DelayServerHandler {
        pub last_tick_time: u32,
        pub tick_count: u32,
        pub accumulated: u32
    }

    impl Handler<Server> for DelayServerHandler {

        fn bind(&mut self, _: &mut Server) {
            self.last_tick_time = precise_time_ms();
        }

        fn tick_connections(
            &mut self, server: &mut Server,
            _: &mut HashMap<ConnectionID, Connection>
        ) {

            // Accumulate time so we can check that the artifical delay
            // was correct for by the servers tick loop
            if self.tick_count > 1 {
                self.accumulated += precise_time_ms() - self.last_tick_time;
            }

            self.last_tick_time = precise_time_ms();
            self.tick_count += 1;

            if self.tick_count == 5 {
                server.shutdown();
            }

            // Fake some load inside of the tick handler
            thread::sleep_ms(75);

        }

    }

    #[test]
    fn test_server_tick_delay() {

        let config = Config {
            send_rate: 10,
            .. Config::default()
        };

        let mut handler = DelayServerHandler {
            last_tick_time: 0,
            tick_count: 0,
            accumulated: 0
        };

        let mut server = Server::new(config);
        server.bind(&mut handler, "127.0.0.1:0").unwrap();

        assert!(handler.accumulated <= 350);

    }

    fn check_messages(conn: &mut Connection) {

        let mut messages = Vec::new();
        for m in conn.received() {
            messages.push(m);
        }

        assert_eq!(messages, [
            [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100].to_vec()

        ].to_vec())

    }

    struct ConnectionServerHandler {
        pub connection_count: i32
    }

    impl Handler<Server> for ConnectionServerHandler {

        fn connection(&mut self, _: &mut Server, _: &mut Connection) {
            self.connection_count += 1;
        }

        fn tick_connections(
            &mut self, server: &mut Server,
            connections: &mut HashMap<ConnectionID, Connection>
        ) {

            // expect 1 message from each connection
            for (id, conn) in connections.iter_mut() {
                match *id {
                    ConnectionID(1) => check_messages(conn),
                    ConnectionID(2) => check_messages(conn),
                    _ => unreachable!("Invalid connection ID")
                }
            }

            server.shutdown();

        }

    }

    #[test]
    fn test_server_connection() {

        let config = Config::default();

        let mut handler = ConnectionServerHandler {
            connection_count: 0
        };

        let socket = MockSocket::new([

            // create a new connection from address 1
            ("127.0.0.1:1234", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 1, // Connection ID
                0, 0, 0, 0,
                0, 0

            ].to_vec()),

            // create a new connection from address 2
            ("127.0.0.1:5678", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 2, // Connection ID
                0, 0, 0, 0,
                0, 0

            ].to_vec()),

            // send message from address 1
            ("127.0.0.1:1234", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 1, // Connection ID
                1, 0, 0, 0,
                0, 0,

                // Hello World
                0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

            ].to_vec()),

            // send message from address 2
            ("127.0.0.1:5678", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 2, // Connection ID
                1, 0, 0, 0,
                0, 0,

                // Hello World
                0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

            ].to_vec())

        ].to_vec());

        let mut server = Server::new(config);
        server.bind_to_socket(&mut handler, socket).unwrap();

        // expect 2 connections
        assert_eq!(handler.connection_count, 2);

    }

    struct ConnectionRemapServerHandler {
        pub connection_count: i32
    }

    impl Handler<Server> for ConnectionRemapServerHandler {

        fn connection(&mut self, _: &mut Server, conn: &mut Connection) {
            let ip = net::Ipv4Addr::new(127, 0, 0, 1);
            let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 1234));
            assert_eq!(conn.peer_addr(), addr);
            self.connection_count += 1;
        }

        fn tick_connections(
            &mut self, server: &mut Server,
            connections: &mut HashMap<ConnectionID, Connection>
        ) {

            // expect 1 message from the connection
            for (id, conn) in connections.iter_mut() {
                let ip = net::Ipv4Addr::new(127, 0, 0, 1);
                let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 5678));
                assert_eq!(*id, ConnectionID(1));
                assert_eq!(conn.peer_addr(), addr);
                check_messages(conn);
            }

            server.shutdown();

        }

    }

    #[test]
    fn test_server_connection_remapping() {

        let config = Config::default();

        let mut handler = ConnectionRemapServerHandler {
            connection_count: 0
        };

        let socket = MockSocket::new([

            // create a new connection from address 1
            ("127.0.0.1:1234", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 1, // Connection ID
                0, 0, 0, 0,
                0, 0

            ].to_vec()),

            // send message from address 2, for connection 1
            ("127.0.0.1:5678", [
                1, 2, 3, 4, // Protocol Header
                0, 0, 0, 1, // Connection ID
                1, 0, 0, 0,
                0, 0,

                // Hello World
                0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

            ].to_vec())

        ].to_vec());

        let mut server = Server::new(config);
        server.bind_to_socket(&mut handler, socket).unwrap();

        // expect 1 connection
        assert_eq!(handler.connection_count, 1);

    }

    // Generic receicing socket mock
    struct MockSocket {
        messages: Option<Vec<(&'static str, Vec<u8>)>>
    }

    impl MockSocket {
        pub fn new(messages: Vec<(&'static str, Vec<u8>)>) -> MockSocket {
            MockSocket {
                messages: Some(messages)
            }
        }
    }

    impl Socket for MockSocket {

        fn reader(&mut self) -> Option<Receiver<(net::SocketAddr, Vec<u8>)>> {

            let (sender, receiver) = channel::<(net::SocketAddr, Vec<u8>)>();
            for (addr, data) in self.messages.take().unwrap().into_iter() {
                let src: net::SocketAddr = addr.parse().ok().unwrap();
                sender.send((src, data.clone())).ok();
            }

            Some(receiver)

        }

        fn send<T: net::ToSocketAddrs>(
            &mut self, _: T, _: &[u8])

        -> Result<usize, Error> {
            Ok(0)
        }

        fn local_addr(&self) -> Result<net::SocketAddr, Error> {
            let ip = net::Ipv4Addr::new(0, 0, 0, 0);
            Ok(net::SocketAddr::V4(net::SocketAddrV4::new(ip, 12345)))
        }

        fn shutdown(&mut self) {

        }

    }

}

<|endoftext|>