<commit_before>use std::ffi::CStr;
use num::FromPrimitive;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };
use std::marker::PhantomData;

#[repr(u32)]
#[derive(Copy, Clone)]
pub enum KerningMode {
    KerningDefault = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags!(
flags LoadFlag: i32 {
    const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
    const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
    const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
    const RENDER                     = ffi::FT_LOAD_RENDER,
    const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
    const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
    const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
    const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
    const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
    const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
    const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
    const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
    const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
    const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
    const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
    const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
    const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
    const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
    const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
    const COLOR                      = ffi::FT_LOAD_COLOR
});

#[derive(Eq, PartialEq, Hash)]
pub struct Face<'a> {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    _phantom: PhantomData<&'a ()>
}

impl <'a> Clone for Face<'a> {
    fn clone(&self) -> Face<'a> {
        unsafe {
            ffi::FT_Reference_Library(self.library_raw);
            ffi::FT_Reference_Face(self.raw);
        }
        Face { ..*self }
    }
}

impl <'a> Face<'a> {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Face<'static> {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
            _phantom: PhantomData
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Attach_File(self.raw, filepathname.as_ptr() as *const i8);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn reference(&self) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Reference_Face(self.raw);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
                                            char_height as ffi::FT_F26Dot6, horz_resolution,
                                            vert_resolution);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_pixel_sizes(&self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_char(&self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_transform(&self, matrix: &Matrix, delta: &Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {

        let mut vec = Vector { x: 0, y: 0 };

        let err_code = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };

        if err_code == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(FromPrimitive::from_i32(err_code).unwrap())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {

        let family_name_ptr = unsafe { (*self.raw).family_name };

        if family_name_ptr.is_null() {
            None
        } else {
            let family_name = unsafe { CStr::from_ptr(family_name_ptr).to_bytes().to_vec() };

            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {

        let style_name_ptr = unsafe { (*self.raw).style_name };

        if style_name_ptr.is_null() {
            None
        } else {
            let style_name = unsafe { CStr::from_ptr(style_name_ptr).to_bytes().to_vec() };

            String::from_utf8(style_name).ok()
        }
    }
}

impl <'a> ::std::fmt::Debug for Face<'a> {
    fn fmt(&self, form: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_string());
        try!(form.write_str("Font Face: "));
        form.write_str(&name[..])
    }
}

impl <'a> Drop for Face<'a> {
    fn drop(&mut self) {
        unsafe {
            match ffi::FT_Done_Face(self.raw) {
                ffi::FT_Err_Ok => {
                    if ffi::FT_Done_Library(self.library_raw) != ffi::FT_Err_Ok {
                        panic!("Failed to deref library");
                    }
                },
                _ => panic!("Failed to drop face"),
            }
        }
    }
}
<commit_msg>added size_metrics to face<commit_after>use std::ffi::CStr;
use num::FromPrimitive;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };
use std::marker::PhantomData;

#[repr(u32)]
#[derive(Copy, Clone)]
pub enum KerningMode {
    KerningDefault = ffi::FT_KERNING_DEFAULT,
    KerningUnfitted = ffi::FT_KERNING_UNFITTED,
    KerningUnscaled = ffi::FT_KERNING_UNSCALED
}

bitflags!(
flags LoadFlag: i32 {
    const DEFAULT                    = ffi::FT_LOAD_DEFAULT,
    const NO_SCALE                   = ffi::FT_LOAD_NO_SCALE,
    const NO_HINTING                 = ffi::FT_LOAD_NO_HINTING,
    const RENDER                     = ffi::FT_LOAD_RENDER,
    const NO_BITMAP                  = ffi::FT_LOAD_NO_BITMAP,
    const VERTICAL_LAYOUT            = ffi::FT_LOAD_VERTICAL_LAYOUT,
    const FORCE_AUTOHINT             = ffi::FT_LOAD_FORCE_AUTOHINT,
    const CROP_BITMAP                = ffi::FT_LOAD_CROP_BITMAP,
    const PEDANTIC                   = ffi::FT_LOAD_PEDANTIC,
    const IGNORE_GLOBAL_ADVANCE_WITH = ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    const NO_RECURSE                 = ffi::FT_LOAD_NO_RECURSE,
    const IGNORE_TRANSFORM           = ffi::FT_LOAD_IGNORE_TRANSFORM,
    const MONOCHROME                 = ffi::FT_LOAD_MONOCHROME,
    const LINEAR_DESIGN              = ffi::FT_LOAD_LINEAR_DESIGN,
    const NO_AUTOHINT                = ffi::FT_LOAD_NO_AUTOHINT,
    const TARGET_NORMAL              = ffi::FT_LOAD_TARGET_NORMAL,
    const TARGET_LIGHT               = ffi::FT_LOAD_TARGET_LIGHT,
    const TARGET_MONO                = ffi::FT_LOAD_TARGET_MONO,
    const TARGET_LCD                 = ffi::FT_LOAD_TARGET_LCD,
    const TARGET_LCD_V               = ffi::FT_LOAD_TARGET_LCD_V,
    const COLOR                      = ffi::FT_LOAD_COLOR
});

#[derive(Eq, PartialEq, Hash)]
pub struct Face<'a> {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    _phantom: PhantomData<&'a ()>
}

impl <'a> Clone for Face<'a> {
    fn clone(&self) -> Face<'a> {
        unsafe {
            ffi::FT_Reference_Library(self.library_raw);
            ffi::FT_Reference_Face(self.raw);
        }
        Face { ..*self }
    }
}

impl <'a> Face<'a> {
    pub fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Face<'static> {
        unsafe {
            ffi::FT_Reference_Library(library_raw);
        }

        Face {
            library_raw: library_raw,
            raw: raw,
            glyph: unsafe { GlyphSlot::from_raw(library_raw, (*raw).glyph) },
            _phantom: PhantomData
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Attach_File(self.raw, filepathname.as_ptr() as *const i8);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn reference(&self) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Reference_Face(self.raw);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
                                            char_height as ffi::FT_F26Dot6, horz_resolution,
                                            vert_resolution);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_pixel_sizes(&self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn load_char(&self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
        unsafe {
            let err = ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits);
            if err == ffi::FT_Err_Ok {
                Ok(())
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn set_transform(&self, matrix: &Matrix, delta: &Vector) {
        unsafe {
            ffi::FT_Set_Transform(self.raw, matrix, delta);
        }
    }

    pub fn get_char_index(&self, charcode: usize) -> u32 {
        unsafe {
            ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong)
        }
    }

    pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
        -> FtResult<Vector> {

        let mut vec = Vector { x: 0, y: 0 };

        let err_code = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };

        if err_code == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(FromPrimitive::from_i32(err_code).unwrap())
        }
    }

    // According to FreeType doc, each time you load a new glyph image,
    // the previous one is erased from the glyph slot.
    #[inline(always)]
    pub fn glyph(&self) -> &GlyphSlot {
        &self.glyph
    }

    #[inline(always)]
    pub fn has_horizontal(&self) -> bool {
        ffi::FT_HAS_HORIZONTAL(self.raw)
    }

    #[inline(always)]
    pub fn has_vertical(&self) -> bool {
        ffi::FT_HAS_VERTICAL(self.raw)
    }

    #[inline(always)]
    pub fn has_kerning(&self) -> bool {
        ffi::FT_HAS_KERNING(self.raw)
    }

    #[inline(always)]
    pub fn is_scalable(&self) -> bool {
        ffi::FT_IS_SCALABLE(self.raw)
    }

    #[inline(always)]
    pub fn is_sfnt(&self) -> bool {
        ffi::FT_IS_SFNT(self.raw)
    }

    #[inline(always)]
    pub fn is_fixed_width(&self) -> bool {
        ffi::FT_IS_FIXED_WIDTH(self.raw)
    }

    #[inline(always)]
    pub fn has_fixed_sizes(&self) -> bool {
        ffi::FT_HAS_FIXED_SIZES(self.raw)
    }

    #[inline(always)]
    pub fn has_glyph_names(&self) -> bool {
        ffi::FT_HAS_GLYPH_NAMES(self.raw)
    }

    #[inline(always)]
    pub fn is_cid_keyed(&self) -> bool {
        ffi::FT_IS_CID_KEYED(self.raw)
    }

    #[inline(always)]
    pub fn is_tricky(&self) -> bool {
        ffi::FT_IS_TRICKY(self.raw)
    }

    #[inline(always)]
    pub fn has_color(&self) -> bool {
        ffi::FT_HAS_COLOR(self.raw)
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_FaceRec {
        unsafe {
            &*self.raw
        }
    }

    #[inline(always)]
    pub fn ascender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).ascender
        }
    }

    #[inline(always)]
    pub fn descender(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).descender
        }
    }

    #[inline(always)]
    pub fn height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).height
        }
    }

    #[inline(always)]
    pub fn max_advance_width(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_width
        }
    }

    #[inline(always)]
    pub fn max_advance_height(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).max_advance_height
        }
    }

    #[inline(always)]
    pub fn underline_position(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_position
        }
    }

    #[inline(always)]
    pub fn underline_thickness(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).underline_thickness
        }
    }

    pub fn family_name(&self) -> Option<String> {

        let family_name_ptr = unsafe { (*self.raw).family_name };

        if family_name_ptr.is_null() {
            None
        } else {
            let family_name = unsafe { CStr::from_ptr(family_name_ptr).to_bytes().to_vec() };

            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {

        let style_name_ptr = unsafe { (*self.raw).style_name };

        if style_name_ptr.is_null() {
            None
        } else {
            let style_name = unsafe { CStr::from_ptr(style_name_ptr).to_bytes().to_vec() };

            String::from_utf8(style_name).ok()
        }
    }

    pub fn size_metrics(&self) -> Option<ffi::FT_Size_Metrics> {
        if self.raw.is_null() {
            None
        } else {
            let size: *mut ffi::FT_SizeRec = unsafe { (*self.raw).size };
            if size.is_null() {
                None
            } else {
                Some(unsafe { (*size).metrics })
            }
        }
    }
}

impl <'a> ::std::fmt::Debug for Face<'a> {
    fn fmt(&self, form: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_string());
        try!(form.write_str("Font Face: "));
        form.write_str(&name[..])
    }
}

impl <'a> Drop for Face<'a> {
    fn drop(&mut self) {
        unsafe {
            match ffi::FT_Done_Face(self.raw) {
                ffi::FT_Err_Ok => {
                    if ffi::FT_Done_Library(self.library_raw) != ffi::FT_Err_Ok {
                        panic!("Failed to deref library");
                    }
                },
                _ => panic!("Failed to drop face"),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::path::PathBuf;
use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write, Read};

pub struct Writer {
    thread: thread::JoinHandle<()>,
    tx: mpsc::SyncSender<WriteMsg>,
}

pub struct Reader {
    pub rx: mpsc::Receiver<ReadMsg>,
}

pub enum WriteMsg {
    Seek(SeekFrom),
    Write(Vec<u8>),
    Finish,
}

pub enum ReadMsg {
    Read(Vec<u8>),
    Finish,
    Error,
}

impl Writer {
    pub fn new(filename: PathBuf) -> Writer {
        let (tx, rx) = mpsc::sync_channel(1024*10);
        let builder = thread::Builder::new().name("file_writer".into());
        let t = builder.spawn(move || {
            let mut f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(false)
                .open(filename)
                .unwrap();

            loop {
                match rx.recv().unwrap() {
                    WriteMsg::Seek(from) => {
                        f.seek(from).unwrap();
                    }
                    WriteMsg::Write(buf) => {
                        f.write_all(&buf[..]).unwrap();
                    }
                    WriteMsg::Finish => {
                        break;
                    }
                }
            }
        }).unwrap();
        Writer {
            thread: t,
            tx: tx,
        }
    }

    pub fn seek(&self, from: SeekFrom) {
        self.tx.send(WriteMsg::Seek(from)).unwrap();
    }

    pub fn write_all(&self, buf: Vec<u8>) {
        self.tx.send(WriteMsg::Write(buf)).unwrap();
    }

    pub fn close(self) {
        self.tx.send(WriteMsg::Finish).unwrap_or_else(|e| error!("{:?}", e));
        if let Err(e) = self.thread.join() {
            error!("\n\n{:?}\n\n", e);
        }
    }
}

impl Reader {
    pub fn new(filename: String) -> Reader {
        let (tx, rx) = mpsc::sync_channel(1024*10);
        let builder = thread::Builder::new().name("file_reader".into());
        let _ = builder.spawn(move || {
            let mut f = File::open(filename).unwrap();
            let mut payload = vec![0; 1350];
            f.seek(SeekFrom::Start(0)).unwrap();
            loop {
                match f.read(&mut payload) {
                    Ok(0) => {
                        tx.send(ReadMsg::Finish).unwrap();
                        break;
                    }
                    Ok(read) => {
                        let mut owned = Vec::with_capacity(read);
                        owned.extend_from_slice(&payload[..read]);
                        tx.send(ReadMsg::Read(owned)).unwrap();
                    }
                    Err(_) => {
                        tx.send(ReadMsg::Error).unwrap();
                        panic!("ruh roh");
                    }
                }
            }
        });

        Reader {
            rx: rx,
        }
    }
}

<commit_msg>warnings when file buffers are full<commit_after>use std::sync::mpsc;
use std::thread;
use std::path::PathBuf;
use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write, Read};

pub struct Writer {
    thread: thread::JoinHandle<()>,
    tx: mpsc::SyncSender<WriteMsg>,
}

pub struct Reader {
    pub rx: mpsc::Receiver<ReadMsg>,
}

pub enum WriteMsg {
    Seek(SeekFrom),
    Write(Vec<u8>),
    Finish,
}

pub enum ReadMsg {
    Read(Vec<u8>),
    Finish,
    Error,
}

impl Writer {
    pub fn new(filename: PathBuf) -> Writer {
        let (tx, rx) = mpsc::sync_channel(1024*10);
        let builder = thread::Builder::new().name("file_writer".into());
        let t = builder.spawn(move || {
            let mut f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(false)
                .open(filename)
                .unwrap();

            loop {
                match rx.recv().unwrap() {
                    WriteMsg::Seek(from) => {
                        f.seek(from).unwrap();
                    }
                    WriteMsg::Write(buf) => {
                        f.write_all(&buf[..]).unwrap();
                    }
                    WriteMsg::Finish => {
                        break;
                    }
                }
            }
        }).unwrap();
        Writer {
            thread: t,
            tx: tx,
        }
    }

    pub fn seek(&self, from: SeekFrom) {
        self.tx.send(WriteMsg::Seek(from)).unwrap();
    }

    pub fn write_all(&self, buf: Vec<u8>) {
        match self.tx.try_send(WriteMsg::Write(buf)) {
            Err(mpsc::TrySendError::Full(d)) => {
                warn!("file write buffer full.");
                self.tx.send(d).unwrap();
            }
            Err(_) => {
                panic!("disconnect");
            }
            Ok(_) => {}
        }
    }

    pub fn close(self) {
        self.tx.send(WriteMsg::Finish).unwrap_or_else(|e| error!("{:?}", e));
        if let Err(e) = self.thread.join() {
            error!("\n\n{:?}\n\n", e);
        }
    }
}

impl Reader {
    pub fn new(filename: String) -> Reader {
        let (tx, rx) = mpsc::sync_channel(1024*10);
        let builder = thread::Builder::new().name("file_reader".into());
        let _ = builder.spawn(move || {
            let mut f = File::open(filename).unwrap();
            let mut payload = vec![0; 1350];
            f.seek(SeekFrom::Start(0)).unwrap();
            loop {
                match f.read(&mut payload) {
                    Ok(0) => {
                        tx.send(ReadMsg::Finish).unwrap();
                        break;
                    }
                    Ok(read) => {
                        let mut owned = Vec::with_capacity(read);
                        owned.extend_from_slice(&payload[..read]);
                        match tx.try_send(ReadMsg::Read(owned)) {
                            Err(mpsc::TrySendError::Full(d)) => {
                                warn!("file read buffer full.");
                                tx.send(d).unwrap();
                            }
                            Err(_) => {
                                panic!("disconnect");
                            }
                            Ok(_) => {}
                        }
                    }
                    Err(_) => {
                        tx.send(ReadMsg::Error).unwrap();
                        panic!("ruh roh");
                    }
                }
            }
        });

        Reader {
            rx: rx,
        }
    }
}

<|endoftext|>


<commit_before>//!
//! FUSE native interface declarations (as of libosxfuse-2.5.5).
//!

#![allow(non_camel_case_types, missing_docs, dead_code)]

use libc::{c_int, c_char};

//
// FUSE arguments (see fuse_opt.h for details)
//

#[repr(C)]
pub struct fuse_args {
    pub argc: c_int,
    pub argv: *const *const c_char,
    pub allocated: c_int,
}

//
// FUSE common (see fuse_common_compat.h for details)
//

extern "system" {
    pub fn fuse_mount_compat25 (mountpoint: *const c_char, args: *const fuse_args) -> c_int;
    pub fn fuse_unmount_compat22 (mountpoint: *const c_char);
}

//
// FUSE kernel (see fuse_kernel.h for details)
//

pub const FUSE_KERNEL_VERSION: u32 = 7;
pub const FUSE_KERNEL_MINOR_VERSION: u32 = 8;
pub const FUSE_ROOT_ID: u64 = 1;

pub struct fuse_attr {
    pub ino: u64,
    pub size: u64,
    pub blocks: u64,
    pub atime: i64,
    pub mtime: i64,
    pub ctime: i64,
    #[cfg(target_os = "macos")]
    pub crtime: i64,            // OS X only
    pub atimensec: i32,
    pub mtimensec: i32,
    pub ctimensec: i32,
    #[cfg(target_os = "macos")]
    pub crtimensec: i32,        // OS X only
    pub mode: u32,
    pub nlink: u32,
    pub uid: u32,
    pub gid: u32,
    pub rdev: u32,
    #[cfg(target_os = "macos")]
    pub flags: u32,             // OS X only, see chflags(2)
}

pub struct fuse_kstatfs {
    pub blocks: u64,            // Total blocks (in units of frsize)
    pub bfree: u64,             // Free blocks
    pub bavail: u64,            // Free blocks for unprivileged users
    pub files: u64,             // Total inodes
    pub ffree: u64,             // Free inodes
    pub bsize: u32,             // Filesystem block size
    pub namelen: u32,           // Maximum filename length
    pub frsize: u32,            // Fundamental file system block size
    pub padding: u32,
    pub spare: [u32; 6],
}

pub struct fuse_file_lock {
    pub start: u64,
    pub end: u64,
    pub typ: u32,
    pub pid: u32,
}

pub mod consts {
    // Bitmasks for fuse_setattr_in.valid
    pub const FATTR_MODE: u32               = 1 << 0;
    pub const FATTR_UID: u32                = 1 << 1;
    pub const FATTR_GID: u32                = 1 << 2;
    pub const FATTR_SIZE: u32               = 1 << 3;
    pub const FATTR_ATIME: u32              = 1 << 4;
    pub const FATTR_MTIME: u32              = 1 << 5;
    pub const FATTR_FH: u32                 = 1 << 6;
    #[cfg(target_os = "macos")]
    pub const FATTR_CRTIME: u32             = 1 << 28;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_CHGTIME: u32            = 1 << 29;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_BKUPTIME: u32           = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_FLAGS: u32              = 1 << 31;  // OS X only

    // Flags returned by the open request
    pub const FOPEN_DIRECT_IO: u32          = 1 << 0;   // bypass page cache for this open file
    pub const FOPEN_KEEP_CACHE: u32         = 1 << 1;   // don't invalidate the data cache on open
    #[cfg(target_os = "macos")]
    pub const FOPEN_PURGE_ATTR: u32         = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FOPEN_PURGE_UBC: u32          = 1 << 31;  // OS X only

    // Init request/reply flags
    pub const FUSE_ASYNC_READ: u32          = 1 << 0;
    pub const FUSE_POSIX_LOCKS: u32         = 1 << 1;
    pub const FUSE_FILE_OPS: u32            = 1 << 2;
    pub const FUSE_ATOMIC_O_TRUNC: u32      = 1 << 3;
    pub const FUSE_EXPORT_SUPPORT: u32      = 1 << 4;
    pub const FUSE_BIG_WRITES: u32          = 1 << 5;
    pub const FUSE_DONT_MASK: u32           = 1 << 6;
    #[cfg(target_os = "macos")]
    pub const FUSE_CASE_INSENSITIVE: u32    = 1 << 29;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FUSE_VOL_RENAME: u32          = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FUSE_XTIMES: u32              = 1 << 31;  // OS X only

    // Release flags
    pub const FUSE_RELEASE_FLUSH: u32       = 1 << 0;
}

#[derive(FromPrimitive)]
pub enum fuse_opcode {
    FUSE_LOOKUP = 1,
    FUSE_FORGET = 2,            // no reply
    FUSE_GETATTR = 3,
    FUSE_SETATTR = 4,
    FUSE_READLINK = 5,
    FUSE_SYMLINK = 6,
    FUSE_MKNOD = 8,
    FUSE_MKDIR = 9,
    FUSE_UNLINK = 10,
    FUSE_RMDIR = 11,
    FUSE_RENAME = 12,
    FUSE_LINK = 13,
    FUSE_OPEN = 14,
    FUSE_READ = 15,
    FUSE_WRITE = 16,
    FUSE_STATFS = 17,
    FUSE_RELEASE = 18,
    FUSE_FSYNC = 20,
    FUSE_SETXATTR = 21,
    FUSE_GETXATTR = 22,
    FUSE_LISTXATTR = 23,
    FUSE_REMOVEXATTR = 24,
    FUSE_FLUSH = 25,
    FUSE_INIT = 26,
    FUSE_OPENDIR = 27,
    FUSE_READDIR = 28,
    FUSE_RELEASEDIR = 29,
    FUSE_FSYNCDIR = 30,
    FUSE_GETLK = 31,
    FUSE_SETLK = 32,
    FUSE_SETLKW = 33,
    FUSE_ACCESS = 34,
    FUSE_CREATE = 35,
    FUSE_INTERRUPT = 36,
    FUSE_BMAP = 37,
    FUSE_DESTROY = 38,
    #[cfg(target_os = "macos")]
    FUSE_SETVOLNAME = 61,       // OS X only
    #[cfg(target_os = "macos")]
    FUSE_GETXTIMES = 62,        // OS X only
    #[cfg(target_os = "macos")]
    FUSE_EXCHANGE = 63,         // OS X only
}

pub struct fuse_entry_out {
    pub nodeid: u64,
    pub generation: u64,
    pub entry_valid: i64,
    pub attr_valid: i64,
    pub entry_valid_nsec: i32,
    pub attr_valid_nsec: i32,
    pub attr: fuse_attr,
}

pub struct fuse_forget_in {
    pub nlookup: u64,
}

pub struct fuse_attr_out {
    pub attr_valid: i64,
    pub attr_valid_nsec: i32,
    pub dummy: u32,
    pub attr: fuse_attr,
}

#[cfg(target_os = "macos")]
pub struct fuse_getxtimes_out { // OS X only
    pub bkuptime: i64,
    pub crtime: i64,
    pub bkuptimensec: i32,
    pub crtimensec: i32,
}

pub struct fuse_mknod_in {
    pub mode: u32,
    pub rdev: u32,
}

pub struct fuse_mkdir_in {
    pub mode: u32,
    pub padding: u32,
}

pub struct fuse_rename_in {
    pub newdir: u64,
}

#[cfg(target_os = "macos")]
pub struct fuse_exchange_in {   // OS X only
    pub olddir: u64,
    pub newdir: u64,
    pub options: u64,
}

pub struct fuse_link_in {
    pub oldnodeid: u64,
}

pub struct fuse_setattr_in {
    pub valid: u32,
    pub padding: u32,
    pub fh: u64,
    pub size: u64,
    pub unused1: u64,
    pub atime: i64,
    pub mtime: i64,
    pub unused2: u64,
    pub atimensec: i32,
    pub mtimensec: i32,
    pub unused3: u32,
    pub mode: u32,
    pub unused4: u32,
    pub uid: u32,
    pub gid: u32,
    pub unused5: u32,
    #[cfg(target_os = "macos")]
    pub bkuptime: i64,          // OS X only
    #[cfg(target_os = "macos")]
    pub chgtime: i64,           // OS X only
    #[cfg(target_os = "macos")]
    pub crtime: i64,            // OS X only
    #[cfg(target_os = "macos")]
    pub bkuptimensec: i32,      // OS X only
    #[cfg(target_os = "macos")]
    pub chgtimensec: i32,       // OS X only
    #[cfg(target_os = "macos")]
    pub crtimensec: i32,        // OS X only
    #[cfg(target_os = "macos")]
    pub flags: u32,             // OS X only
}

pub struct fuse_open_in {
    pub flags: u32,
    pub mode: u32,
}

pub struct fuse_open_out {
    pub fh: u64,
    pub open_flags: u32,
    pub padding: u32,
}

pub struct fuse_release_in {
    pub fh: u64,
    pub flags: u32,
    pub release_flags: u32,
    pub lock_owner: u64,
}

pub struct fuse_flush_in {
    pub fh: u64,
    pub unused: u32,
    pub padding: u32,
    pub lock_owner: u64,
}

pub struct fuse_read_in {
    pub fh: u64,
    pub offset: u64,
    pub size: u32,
    pub padding: u32,
}

pub struct fuse_write_in {
    pub fh: u64,
    pub offset: u64,
    pub size: u32,
    pub write_flags: u32,
}

pub struct fuse_write_out {
    pub size: u32,
    pub padding: u32,
}

pub struct fuse_statfs_out {
    pub st: fuse_kstatfs,
}

pub struct fuse_fsync_in {
    pub fh: u64,
    pub fsync_flags: u32,
    pub padding: u32,
}

pub struct fuse_setxattr_in {
    pub size: u32,
    pub flags: u32,
    #[cfg(target_os = "macos")]
    pub position: u32,          // OS X only
    #[cfg(target_os = "macos")]
    pub padding: u32,           // OS X only
}

pub struct fuse_getxattr_in {
    pub size: u32,
    pub padding: u32,
    #[cfg(target_os = "macos")]
    pub position: u32,          // OS X only
    #[cfg(target_os = "macos")]
    pub padding2: u32,          // OS X only
}

pub struct fuse_getxattr_out {
    pub size: u32,
    pub padding: u32,
}

pub struct fuse_lk_in {
    pub fh: u64,
    pub owner: u64,
    pub lk: fuse_file_lock,
}

pub struct fuse_lk_out {
    pub lk: fuse_file_lock,
}

pub struct fuse_access_in {
    pub mask: u32,
    pub padding: u32,
}

pub struct fuse_init_in {
    pub major: u32,
    pub minor: u32,
    pub max_readahead: u32,
    pub flags: u32,
}

pub struct fuse_init_out {
    pub major: u32,
    pub minor: u32,
    pub max_readahead: u32,
    pub flags: u32,
    pub unused: u32,
    pub max_write: u32,
}

pub struct fuse_interrupt_in {
    pub unique: u64,
}

pub struct fuse_bmap_in {
    pub block: u64,
    pub blocksize: u32,
    pub padding: u32,
}

pub struct fuse_bmap_out {
    pub block: u64,
}

pub struct fuse_in_header {
    pub len: u32,
    pub opcode: u32,
    pub unique: u64,
    pub nodeid: u64,
    pub uid: u32,
    pub gid: u32,
    pub pid: u32,
    pub padding: u32,
}

pub struct fuse_out_header {
    pub len: u32,
    pub error: i32,
    pub unique: u64,
}

pub struct fuse_dirent {
    pub ino: u64,
    pub off: u64,
    pub namelen: u32,
    pub typ: u32,
    // followed by name of namelen bytes
}
<commit_msg>Use repr(C) on all ffi structs to ensure the correct memory layout<commit_after>//!
//! FUSE native interface declarations (as of libosxfuse-2.5.5).
//!

#![allow(non_camel_case_types, missing_docs, dead_code)]

use libc::{c_int, c_char};

//
// FUSE arguments (see fuse_opt.h for details)
//

#[repr(C)]
pub struct fuse_args {
    pub argc: c_int,
    pub argv: *const *const c_char,
    pub allocated: c_int,
}

//
// FUSE common (see fuse_common_compat.h for details)
//

extern "system" {
    pub fn fuse_mount_compat25 (mountpoint: *const c_char, args: *const fuse_args) -> c_int;
    pub fn fuse_unmount_compat22 (mountpoint: *const c_char);
}

//
// FUSE kernel (see fuse_kernel.h for details)
//

pub const FUSE_KERNEL_VERSION: u32 = 7;
pub const FUSE_KERNEL_MINOR_VERSION: u32 = 8;
pub const FUSE_ROOT_ID: u64 = 1;

#[repr(C)]
pub struct fuse_attr {
    pub ino: u64,
    pub size: u64,
    pub blocks: u64,
    pub atime: i64,
    pub mtime: i64,
    pub ctime: i64,
    #[cfg(target_os = "macos")]
    pub crtime: i64,            // OS X only
    pub atimensec: i32,
    pub mtimensec: i32,
    pub ctimensec: i32,
    #[cfg(target_os = "macos")]
    pub crtimensec: i32,        // OS X only
    pub mode: u32,
    pub nlink: u32,
    pub uid: u32,
    pub gid: u32,
    pub rdev: u32,
    #[cfg(target_os = "macos")]
    pub flags: u32,             // OS X only, see chflags(2)
}

#[repr(C)]
pub struct fuse_kstatfs {
    pub blocks: u64,            // Total blocks (in units of frsize)
    pub bfree: u64,             // Free blocks
    pub bavail: u64,            // Free blocks for unprivileged users
    pub files: u64,             // Total inodes
    pub ffree: u64,             // Free inodes
    pub bsize: u32,             // Filesystem block size
    pub namelen: u32,           // Maximum filename length
    pub frsize: u32,            // Fundamental file system block size
    pub padding: u32,
    pub spare: [u32; 6],
}

#[repr(C)]
pub struct fuse_file_lock {
    pub start: u64,
    pub end: u64,
    pub typ: u32,
    pub pid: u32,
}

pub mod consts {
    // Bitmasks for fuse_setattr_in.valid
    pub const FATTR_MODE: u32               = 1 << 0;
    pub const FATTR_UID: u32                = 1 << 1;
    pub const FATTR_GID: u32                = 1 << 2;
    pub const FATTR_SIZE: u32               = 1 << 3;
    pub const FATTR_ATIME: u32              = 1 << 4;
    pub const FATTR_MTIME: u32              = 1 << 5;
    pub const FATTR_FH: u32                 = 1 << 6;
    #[cfg(target_os = "macos")]
    pub const FATTR_CRTIME: u32             = 1 << 28;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_CHGTIME: u32            = 1 << 29;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_BKUPTIME: u32           = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FATTR_FLAGS: u32              = 1 << 31;  // OS X only

    // Flags returned by the open request
    pub const FOPEN_DIRECT_IO: u32          = 1 << 0;   // bypass page cache for this open file
    pub const FOPEN_KEEP_CACHE: u32         = 1 << 1;   // don't invalidate the data cache on open
    #[cfg(target_os = "macos")]
    pub const FOPEN_PURGE_ATTR: u32         = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FOPEN_PURGE_UBC: u32          = 1 << 31;  // OS X only

    // Init request/reply flags
    pub const FUSE_ASYNC_READ: u32          = 1 << 0;
    pub const FUSE_POSIX_LOCKS: u32         = 1 << 1;
    pub const FUSE_FILE_OPS: u32            = 1 << 2;
    pub const FUSE_ATOMIC_O_TRUNC: u32      = 1 << 3;
    pub const FUSE_EXPORT_SUPPORT: u32      = 1 << 4;
    pub const FUSE_BIG_WRITES: u32          = 1 << 5;
    pub const FUSE_DONT_MASK: u32           = 1 << 6;
    #[cfg(target_os = "macos")]
    pub const FUSE_CASE_INSENSITIVE: u32    = 1 << 29;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FUSE_VOL_RENAME: u32          = 1 << 30;  // OS X only
    #[cfg(target_os = "macos")]
    pub const FUSE_XTIMES: u32              = 1 << 31;  // OS X only

    // Release flags
    pub const FUSE_RELEASE_FLUSH: u32       = 1 << 0;
}

#[repr(C)]
#[derive(FromPrimitive)]
pub enum fuse_opcode {
    FUSE_LOOKUP = 1,
    FUSE_FORGET = 2,            // no reply
    FUSE_GETATTR = 3,
    FUSE_SETATTR = 4,
    FUSE_READLINK = 5,
    FUSE_SYMLINK = 6,
    FUSE_MKNOD = 8,
    FUSE_MKDIR = 9,
    FUSE_UNLINK = 10,
    FUSE_RMDIR = 11,
    FUSE_RENAME = 12,
    FUSE_LINK = 13,
    FUSE_OPEN = 14,
    FUSE_READ = 15,
    FUSE_WRITE = 16,
    FUSE_STATFS = 17,
    FUSE_RELEASE = 18,
    FUSE_FSYNC = 20,
    FUSE_SETXATTR = 21,
    FUSE_GETXATTR = 22,
    FUSE_LISTXATTR = 23,
    FUSE_REMOVEXATTR = 24,
    FUSE_FLUSH = 25,
    FUSE_INIT = 26,
    FUSE_OPENDIR = 27,
    FUSE_READDIR = 28,
    FUSE_RELEASEDIR = 29,
    FUSE_FSYNCDIR = 30,
    FUSE_GETLK = 31,
    FUSE_SETLK = 32,
    FUSE_SETLKW = 33,
    FUSE_ACCESS = 34,
    FUSE_CREATE = 35,
    FUSE_INTERRUPT = 36,
    FUSE_BMAP = 37,
    FUSE_DESTROY = 38,
    #[cfg(target_os = "macos")]
    FUSE_SETVOLNAME = 61,       // OS X only
    #[cfg(target_os = "macos")]
    FUSE_GETXTIMES = 62,        // OS X only
    #[cfg(target_os = "macos")]
    FUSE_EXCHANGE = 63,         // OS X only
}

#[repr(C)]
pub struct fuse_entry_out {
    pub nodeid: u64,
    pub generation: u64,
    pub entry_valid: i64,
    pub attr_valid: i64,
    pub entry_valid_nsec: i32,
    pub attr_valid_nsec: i32,
    pub attr: fuse_attr,
}

#[repr(C)]
pub struct fuse_forget_in {
    pub nlookup: u64,
}

#[repr(C)]
pub struct fuse_attr_out {
    pub attr_valid: i64,
    pub attr_valid_nsec: i32,
    pub dummy: u32,
    pub attr: fuse_attr,
}

#[cfg(target_os = "macos")]
#[repr(C)]
pub struct fuse_getxtimes_out { // OS X only
    pub bkuptime: i64,
    pub crtime: i64,
    pub bkuptimensec: i32,
    pub crtimensec: i32,
}

#[repr(C)]
pub struct fuse_mknod_in {
    pub mode: u32,
    pub rdev: u32,
}

#[repr(C)]
pub struct fuse_mkdir_in {
    pub mode: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_rename_in {
    pub newdir: u64,
}

#[cfg(target_os = "macos")]
#[repr(C)]
pub struct fuse_exchange_in {   // OS X only
    pub olddir: u64,
    pub newdir: u64,
    pub options: u64,
}

#[repr(C)]
pub struct fuse_link_in {
    pub oldnodeid: u64,
}

#[repr(C)]
pub struct fuse_setattr_in {
    pub valid: u32,
    pub padding: u32,
    pub fh: u64,
    pub size: u64,
    pub unused1: u64,
    pub atime: i64,
    pub mtime: i64,
    pub unused2: u64,
    pub atimensec: i32,
    pub mtimensec: i32,
    pub unused3: u32,
    pub mode: u32,
    pub unused4: u32,
    pub uid: u32,
    pub gid: u32,
    pub unused5: u32,
    #[cfg(target_os = "macos")]
    pub bkuptime: i64,          // OS X only
    #[cfg(target_os = "macos")]
    pub chgtime: i64,           // OS X only
    #[cfg(target_os = "macos")]
    pub crtime: i64,            // OS X only
    #[cfg(target_os = "macos")]
    pub bkuptimensec: i32,      // OS X only
    #[cfg(target_os = "macos")]
    pub chgtimensec: i32,       // OS X only
    #[cfg(target_os = "macos")]
    pub crtimensec: i32,        // OS X only
    #[cfg(target_os = "macos")]
    pub flags: u32,             // OS X only
}

#[repr(C)]
pub struct fuse_open_in {
    pub flags: u32,
    pub mode: u32,
}

#[repr(C)]
pub struct fuse_open_out {
    pub fh: u64,
    pub open_flags: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_release_in {
    pub fh: u64,
    pub flags: u32,
    pub release_flags: u32,
    pub lock_owner: u64,
}

#[repr(C)]
pub struct fuse_flush_in {
    pub fh: u64,
    pub unused: u32,
    pub padding: u32,
    pub lock_owner: u64,
}

#[repr(C)]
pub struct fuse_read_in {
    pub fh: u64,
    pub offset: u64,
    pub size: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_write_in {
    pub fh: u64,
    pub offset: u64,
    pub size: u32,
    pub write_flags: u32,
}

#[repr(C)]
pub struct fuse_write_out {
    pub size: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_statfs_out {
    pub st: fuse_kstatfs,
}

#[repr(C)]
pub struct fuse_fsync_in {
    pub fh: u64,
    pub fsync_flags: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_setxattr_in {
    pub size: u32,
    pub flags: u32,
    #[cfg(target_os = "macos")]
    pub position: u32,          // OS X only
    #[cfg(target_os = "macos")]
    pub padding: u32,           // OS X only
}

#[repr(C)]
pub struct fuse_getxattr_in {
    pub size: u32,
    pub padding: u32,
    #[cfg(target_os = "macos")]
    pub position: u32,          // OS X only
    #[cfg(target_os = "macos")]
    pub padding2: u32,          // OS X only
}

#[repr(C)]
pub struct fuse_getxattr_out {
    pub size: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_lk_in {
    pub fh: u64,
    pub owner: u64,
    pub lk: fuse_file_lock,
}

#[repr(C)]
pub struct fuse_lk_out {
    pub lk: fuse_file_lock,
}

#[repr(C)]
pub struct fuse_access_in {
    pub mask: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_init_in {
    pub major: u32,
    pub minor: u32,
    pub max_readahead: u32,
    pub flags: u32,
}

#[repr(C)]
pub struct fuse_init_out {
    pub major: u32,
    pub minor: u32,
    pub max_readahead: u32,
    pub flags: u32,
    pub unused: u32,
    pub max_write: u32,
}

#[repr(C)]
pub struct fuse_interrupt_in {
    pub unique: u64,
}

#[repr(C)]
pub struct fuse_bmap_in {
    pub block: u64,
    pub blocksize: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_bmap_out {
    pub block: u64,
}

#[repr(C)]
pub struct fuse_in_header {
    pub len: u32,
    pub opcode: u32,
    pub unique: u64,
    pub nodeid: u64,
    pub uid: u32,
    pub gid: u32,
    pub pid: u32,
    pub padding: u32,
}

#[repr(C)]
pub struct fuse_out_header {
    pub len: u32,
    pub error: i32,
    pub unique: u64,
}

#[repr(C)]
pub struct fuse_dirent {
    pub ino: u64,
    pub off: u64,
    pub namelen: u32,
    pub typ: u32,
    // followed by name of namelen bytes
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Added doc for GroupingMap::fold_first<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>#![crate_id = "hamcrest"]
#![crate_type = "lib"]

extern crate collections;
extern crate debug;

pub use core::{assert_that,expect,success,Matcher,MatchResult,SelfDescribing};
pub use matchers::is::{is,is_not};
pub use not = matchers::is::is_not;
pub use matchers::none::{none};
pub use matchers::equal_to::equal_to;
pub use matchers::existing_path::{existing_path,existing_file,existing_dir};
pub use matchers::vecs::{of_len,contains};

pub mod core;
pub mod matchers {
  pub mod equal_to;
  pub mod existing_path;
  pub mod is;
  pub mod none;
  pub mod vecs;
}
<commit_msg>crate_id -> crate_name<commit_after>#![crate_name = "hamcrest"]
#![crate_type = "lib"]

extern crate collections;
extern crate debug;

pub use core::{assert_that,expect,success,Matcher,MatchResult,SelfDescribing};
pub use matchers::is::{is,is_not};
pub use not = matchers::is::is_not;
pub use matchers::none::{none};
pub use matchers::equal_to::equal_to;
pub use matchers::existing_path::{existing_path,existing_file,existing_dir};
pub use matchers::vecs::{of_len,contains};

pub mod core;
pub mod matchers {
  pub mod equal_to;
  pub mod existing_path;
  pub mod is;
  pub mod none;
  pub mod vecs;
}
<|endoftext|>


<commit_before>extern crate glium;
extern crate time;

use std::collections::HashSet;

use super::{Result, Draw, Drawable, Texture};
use time::precise_time_s as time_s;

use glium::{Frame, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

/// A struct to keep your "game" in
pub struct Game<'a, S, L, R>  where L: FnMut(&mut S, LogicArgs), R: FnMut(&S, RenderArgs){
    /// An object that will parsed into the logic and render methods
    pub shared: S,
    logic : L,
    render: R,
    draw  : Draw<'a>,
}

impl<'a, S, L, R> Game<'a, S, L, R> where L: FnMut(&mut S, LogicArgs), R: FnMut(&S, RenderArgs){
    /// Creates a new `Game` with a `Draw` and two closures
    pub fn new(draw: Draw<'a>, logic: L, render: R) -> Game<'a, (), L, R>
    where L: FnMut(&mut (), LogicArgs), R: FnMut(&(), RenderArgs){
        Game{
            shared: (),
            logic : logic,
            render: render,
            draw  : draw,
        }
    }

    /// Creates a new `Game` with a `Draw`, a shared value, and two closures
    pub fn with_shared(draw: Draw<'a>, shared: S, logic: L, render: R) -> Self{
        Game{
            shared: shared,
            logic : logic,
            render: render,
            draw  : draw,
        }
    }

    /// Runs the `Game` until the window is closed
    pub fn run_until_closed(mut self){
        let mut last = time_s();
        let mut down_keys: HashSet<VirtualKeyCode> = HashSet::new();
        let mut mousepos = (0, 0);

        'main: loop {
            let mut keys = Vec::new();

            for ev in self.draw.get_display().poll_events() {
                match ev {
                    Event::Closed => break 'main,
                    Event::KeyboardInput(es, _, vkc) => match es{
                        ElementState::Pressed  => {
                            if let Some(vkc) = vkc{
                                down_keys.insert( vkc);
                                keys.push((true , vkc));
                            }
                        },
                        ElementState::Released => {
                            if let Some(vkc) = vkc{
                                down_keys.remove(&vkc);
                                keys.push((false, vkc));
                            }
                        }
                    },
                    Event::MouseMoved(pos) => mousepos = pos,
                    _ => ()
                }
            }

            let now = time_s();

            let delta = now-last;

            last = now;

            (self.logic)(&mut self.shared, LogicArgs{
                delta    :  delta,
                keyevents: &keys,
                down_keys: &down_keys,
                mousepos :  mousepos
            });

            // Do rendering
            let mut target = self.draw.get_display().draw();
            target.clear_color(0.0, 0.0, 1.0, 1.0);

            (self.render)(&self.shared, RenderArgs{
                target: &mut target,
                draw  : &self.draw
            });

            target.finish().unwrap()
        }
    }
}

/// Wraps all useful info about what has happened (e.g. events) together
#[derive(Debug)]
pub struct LogicArgs<'a>{
    /// The delta time since last frame
    pub delta    : f64,
    /// The current position of the mouse
    pub mousepos : (i32, i32),
    /// A vector of all key events that happened
    pub keyevents: &'a [(bool, VirtualKeyCode)],

    /// A `HashSet` of all keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> LogicArgs<'a>{
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

use std::ops::Deref;

/// Wraps everything needed to render together
pub struct RenderArgs<'a>{
    /// Object used to draw on the buffer.
    /// Generally, you shouldn't have to access this directly.
    pub target: &'a mut glium::Frame,
    /// Reference to the `Draw` instance
    /// Generally, you shouldn't have to access this directly.
    pub draw  : &'a Draw<'a>
}

impl<'a> RenderArgs<'a>{
    /// Uses `Draw` to draw an iterator of `Drawable`s onto the screen
    pub fn draw_drawables<'d, D: 'd + Drawable, I: IntoIterator<Item = &'d D>>(&mut self, drawables: I) -> Result<()>{
        self.draw.draw_drawables(self.target, drawables)
    }

    /// Uses `Draw` to draw a texture onto the screen
    pub fn draw_texture(&mut self, texture: &Texture, rotation: f32, x: f32, y: f32) -> Result<()>{
        self.draw.draw_texture(self.target, texture, rotation, x, y)
    }
}

impl<'a> Deref for RenderArgs<'a>{
    type Target = Draw<'a>;

    fn deref(&self) -> &Draw<'a>{
        self.draw
    }
}

/// Macro for easily doing things if particular keys are down
/// # Examples
/// Basic usage:
///
/// ```ignore
/// #[macro_use]
/// extern crate korome;
///
/// use korome::{GameLogic, LogicArgs};
///
/// struct Logic {
///     player_y: f32
/// }
///
/// impl GameLogic for Logic{
///     fn logic(&self, l_args: LogicArgs){
///         is_down!(l_args;
///             W, Up => {
///                 self.player_y -= l_args.delta() as f32
///             },
///             S, Down => {
///                 self.player_y += l_args.delta() as f32
///             }
///         );
///     }
///     // the rest of implementation omitted
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $l_args:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $l_args.is_down(&glium::glutin::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<commit_msg>Little optimisation in event loop<commit_after>extern crate glium;
extern crate time;

use std::collections::HashSet;

use super::{Result, Draw, Drawable, Texture};
use time::precise_time_s as time_s;

use glium::{Frame, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

/// A struct to keep your "game" in
pub struct Game<'a, S, L, R>  where L: FnMut(&mut S, LogicArgs), R: FnMut(&S, RenderArgs){
    /// An object that will parsed into the logic and render methods
    pub shared: S,
    logic : L,
    render: R,
    draw  : Draw<'a>,
}

impl<'a, S, L, R> Game<'a, S, L, R> where L: FnMut(&mut S, LogicArgs), R: FnMut(&S, RenderArgs){
    /// Creates a new `Game` with a `Draw` and two closures
    pub fn new(draw: Draw<'a>, logic: L, render: R) -> Game<'a, (), L, R>
    where L: FnMut(&mut (), LogicArgs), R: FnMut(&(), RenderArgs){
        Game{
            shared: (),
            logic : logic,
            render: render,
            draw  : draw,
        }
    }

    /// Creates a new `Game` with a `Draw`, a shared value, and two closures
    pub fn with_shared(draw: Draw<'a>, shared: S, logic: L, render: R) -> Self{
        Game{
            shared: shared,
            logic : logic,
            render: render,
            draw  : draw,
        }
    }

    /// Runs the `Game` until the window is closed
    pub fn run_until_closed(mut self){
        let mut last = time_s();
        let mut down_keys: HashSet<VirtualKeyCode> = HashSet::new();
        let mut mousepos = (0, 0);

        'main: loop {
            let mut keys = Vec::new();

            for ev in self.draw.get_display().poll_events() {
                match ev {
                    Event::Closed => break 'main,
                    Event::KeyboardInput(es, _, Some(vkc)) => match es{
                        ElementState::Pressed  => {
                            down_keys.insert( vkc);
                            keys.push((true , vkc));
                        },
                        ElementState::Released => {
                            down_keys.remove(&vkc);
                            keys.push((false, vkc));
                        }
                    },
                    Event::MouseMoved(pos) => mousepos = pos,
                    _ => ()
                }
            }

            let now = time_s();

            let delta = now-last;

            last = now;

            (self.logic)(&mut self.shared, LogicArgs{
                delta    :  delta,
                keyevents: &keys,
                down_keys: &down_keys,
                mousepos :  mousepos
            });

            // Do rendering
            let mut target = self.draw.get_display().draw();
            target.clear_color(0.0, 0.0, 1.0, 1.0);

            (self.render)(&self.shared, RenderArgs{
                target: &mut target,
                draw  : &self.draw
            });

            target.finish().unwrap()
        }
    }
}

/// Wraps all useful info about what has happened (e.g. events) together
#[derive(Debug)]
pub struct LogicArgs<'a>{
    /// The delta time since last frame
    pub delta    : f64,
    /// The current position of the mouse
    pub mousepos : (i32, i32),
    /// A vector of all key events that happened
    pub keyevents: &'a [(bool, VirtualKeyCode)],

    /// A `HashSet` of all keys that are pressed down
    down_keys: &'a HashSet<VirtualKeyCode>
}

impl<'a> LogicArgs<'a>{
    /// Checks whether a key is pressed down
    pub fn is_down(&self, key: &VirtualKeyCode) -> bool{
        self.down_keys.contains(key)
    }
}

use std::ops::Deref;

/// Wraps everything needed to render together
pub struct RenderArgs<'a>{
    /// Object used to draw on the buffer.
    /// Generally, you shouldn't have to access this directly.
    pub target: &'a mut glium::Frame,
    /// Reference to the `Draw` instance
    /// Generally, you shouldn't have to access this directly.
    pub draw  : &'a Draw<'a>
}

impl<'a> RenderArgs<'a>{
    /// Uses `Draw` to draw an iterator of `Drawable`s onto the screen
    pub fn draw_drawables<'d, D: 'd + Drawable, I: IntoIterator<Item = &'d D>>(&mut self, drawables: I) -> Result<()>{
        self.draw.draw_drawables(self.target, drawables)
    }

    /// Uses `Draw` to draw a texture onto the screen
    pub fn draw_texture(&mut self, texture: &Texture, rotation: f32, x: f32, y: f32) -> Result<()>{
        self.draw.draw_texture(self.target, texture, rotation, x, y)
    }
}

impl<'a> Deref for RenderArgs<'a>{
    type Target = Draw<'a>;

    fn deref(&self) -> &Draw<'a>{
        self.draw
    }
}

/// Macro for easily doing things if particular keys are down
/// # Examples
/// Basic usage:
///
/// ```ignore
/// #[macro_use]
/// extern crate korome;
///
/// use korome::{GameLogic, LogicArgs};
///
/// struct Logic {
///     player_y: f32
/// }
///
/// impl GameLogic for Logic{
///     fn logic(&self, l_args: LogicArgs){
///         is_down!(l_args;
///             W, Up => {
///                 self.player_y -= l_args.delta() as f32
///             },
///             S, Down => {
///                 self.player_y += l_args.delta() as f32
///             }
///         );
///     }
///     // the rest of implementation omitted
/// }
/// ```
#[macro_export]
macro_rules! is_down{
    ( $l_args:ident; $( $( $key:ident ),+ => $b:block ),+ ) => {{
        $( if $( $l_args.is_down(&glium::glutin::VirtualKeyCode::$key) )||+ $b )+
    }}
}
<|endoftext|>


<commit_before>//! Game loop.

// External crates.
use graphics::Context;

// Local crate.
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use AssetStore;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    ///
    /// `context` is a Rust-Graphics context.
    /// `gl` is the Piston OpenGL back-end for Rust-Graphics.
    fn render(&self, _context: &Context, _args: &mut RenderArgs) {}

    /// Update the physical state of the game.
    ///
    /// `dt` is the delta time from last update in seconds.
    fn update(&mut self, _args: &mut UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self, _asset_store: &mut AssetStore) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Executes a game loop.
    ///
    /// The loop continues until `should_close` returns true.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            &GameIteratorSettings {
                updates_per_second: 120,
                max_frames_per_second: 60
            });

        self.load(asset_store);

        loop {
            match game_iter.next() {
                None => { break }
                Some(e) => match e {
                    Render(mut args) => self.render(
                        &Context::abs(
                            args.width as f64,
                            args.height as f64
                        ),
                        &mut args
                    ),
                    Update(mut args) => self.update(&mut args),
                    KeyPress(args) => self.key_press(&args),
                    KeyRelease(args) => self.key_release(&args),
                    MousePress(args) => self.mouse_press(&args),
                    MouseRelease(args) => self.mouse_release(&args),
                    MouseMove(args) => self.mouse_move(&args),
                    MouseRelativeMove(args) => self.mouse_relative_move(&args),

                }
            }
        }
    }
}

<commit_msg>Added `event` method on `Game` trait<commit_after>//! Game loop.

// External crates.
use graphics::Context;

// Local crate.
use GameEvent;
use GameWindow = game_window::GameWindow;
use GameIteratorSettings;
use AssetStore;
use GameIterator;
use KeyPress;
use KeyPressArgs;
use KeyRelease;
use KeyReleaseArgs;
use MouseMove;
use MouseMoveArgs;
use MouseRelativeMove;
use MouseRelativeMoveArgs;
use MousePress;
use MousePressArgs;
use MouseRelease;
use MouseReleaseArgs;
use Render;
use RenderArgs;
use Update;
use UpdateArgs;

/// Implemented by game applications.
pub trait Game {
    /// Render graphics.
    ///
    /// `context` is a Rust-Graphics context.
    /// `gl` is the Piston OpenGL back-end for Rust-Graphics.
    fn render(&self, _context: &Context, _args: &mut RenderArgs) {}

    /// Update the physical state of the game.
    ///
    /// `dt` is the delta time from last update in seconds.
    fn update(&mut self, _args: &mut UpdateArgs) {}

    /// Perform tasks for loading before showing anything.
    fn load(&mut self, _asset_store: &mut AssetStore) {}

    /// User pressed a key.
    ///
    /// This can be overridden to handle key pressed events.
    fn key_press(&mut self, _args: &KeyPressArgs) {}

    /// User released a key.
    ///
    /// This can be overridden to handle key released events.
    fn key_release(&mut self, _args: &KeyReleaseArgs) {}

    /// Pressed a mouse button.
    fn mouse_press(&mut self, _args: &MousePressArgs) {}

    /// Released a mouse button.
    fn mouse_release(&mut self, _args: &MouseReleaseArgs) {}

    /// Moved mouse cursor.
    fn mouse_move(&mut self, _args: &MouseMoveArgs) {}

    /// Moved mouse relative, not bounded by cursor.
    fn mouse_relative_move(&mut self, _args: &MouseRelativeMoveArgs) {}

    /// Handles a game event.
    fn event(&mut self, event: &mut GameEvent) {
        match *event {
            Render(ref mut args) => self.render(
                &Context::abs(
                    args.width as f64,
                    args.height as f64
                ),
                args
            ),
            Update(ref mut args) => self.update(args),
            KeyPress(ref args) => self.key_press(args),
            KeyRelease(ref args) => self.key_release(args),
            MousePress(ref args) => self.mouse_press(args),
            MouseRelease(ref args) => self.mouse_release(args),
            MouseMove(ref args) => self.mouse_move(args),
            MouseRelativeMove(ref args) => self.mouse_relative_move(args),
        }
    }

    /// Executes a game loop.
    fn run<W: GameWindow>(
        &mut self,
        game_window: &mut W,
        asset_store: &mut AssetStore
    ) {
        let mut game_iter = GameIterator::new(
            game_window,
            &GameIteratorSettings {
                updates_per_second: 120,
                max_frames_per_second: 60
            });

        self.load(asset_store);

        loop {
            match game_iter.next() {
                None => break,
                Some(mut e) => self.event(&mut e)
            }
        }
    }
}

<|endoftext|>


<commit_before>use world::World;
use piston_window::*;
use camera::Camera;
use cgmath::{Vector2, vec3};
use cgmath::prelude::*;
use color::*;
use car::*;
use piston_window::Ellipse;
use bot::BoxRules;
use std::cell::RefCell;
use std::ops::DerefMut;
use std::time::Instant;

// `Game` contains every things to run the game
pub struct Game {
    config: GameConfig,
    world: World, // All objects in the game
    window: PistonWindow,
    bot_rules: BoxRules, // Rules to create a new bot
    camera: Camera, // Camera for rendering
    state: State, // Current state of game
    // Wrap these caches in `RefCell` to allow interior mutability
    glyphs: RefCell<Glyphs>, // Font cache
    ellipse: RefCell<Ellipse>, // Model to draw a circle
}

struct State {
    pub turn: Turn, // Presents movement of player
    pub sprint: bool, // Player is speeding-up or not
    pub spawn: f64, // Count down time to spawn a new bot
    pub ended: bool, // Game is over or not
    pub game_speed: f64, // Game speed in addition to player's speed
    pub jump_timeout: f64, // Count down to allow the next jump
    pub rotate_cam: bool, // Allow rotation of camera or not
    pub bullets: i64, // The number of bullets left
    pub recharge: f64, // Bullets recharge time
    pub fps: f64, // Real fps of game
    pub last_frame: Instant, // Moment of the last draw
}

pub enum Turn { Left, Right, None, }

// Configurable game's contansts.
// A tuple presents a range of something.
#[derive(Serialize, Deserialize, Clone)]
pub struct GameConfig {
    pub title: String,
    pub screen_size: ::Pixel,
    pub ups: u64, // Update per second
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64), // min and max player speed
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3], // Range of bot's size
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64, // Height of camera (from player)
    pub camera_distance: f64, // Distance from camera to player
    pub decor_distance: f64, // Distance between each decoration
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64, // The increase of game_speed
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64, // Number of bullets
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
    pub zoom_in: bool, // If true, zoom-in while on stare mode
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title.clone(), [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build()
            .expect("Cannot create window.");
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let glyphs = Glyphs::new("resources/Ubuntu-R.ttf", window.factory.clone())
            .expect("Unable to load font.");
        let bot_rules = BoxRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
            fps: 0.,
            last_frame: Instant::now(),
        };
        let ellipse = Ellipse {
            color: BLACK.alpha(0.).into(),
            border: Some(ellipse::Border {
                color: RED.alpha(0.5).into(),
                radius: 1.,
            }),
            resolution: 360,
        };

        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
            glyphs: RefCell::new(glyphs),
            ellipse: RefCell::new(ellipse),
        }
    }

    fn new_camera<T: Car>(config: &GameConfig, player: &T) -> Camera {
        Camera::new(
            config.screen_size.clone(),
            vec3(0., config.camera_height, -config.camera_distance) + player.pos()
        )
    }
    // Re-calculate fps
    fn update_fps(&mut self) {
        let d = self.state.last_frame.elapsed();
        self.state.last_frame = Instant::now();
        self.state.fps = 1. / (d.as_secs() as f64 + 1e-9*d.subsec_nanos() as f64);
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => {
                    self.update_fps();
                    self.draw(&e);
                },
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }
    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.jump();
            },
            Button::Mouse(MouseButton::Right) => {
                if self.config.zoom_in {
                    self.camera.zoom_in();
                }
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = vec3(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        // Return a horizontal bar
        macro_rules! bar {
            ($curr: expr, $full: expr) => {
                [0.,
                self.config.screen_size.h as f64 - 20.,
                self.config.screen_size.w as f64/2.*$curr/$full,
                self.config.screen_size.h as f64,]
            };
        }
        let jump_bar = bar!(self.state.jump_timeout, self.config.jump_timeout);
        let recharge_bar = bar!(self.state.recharge, self.config.recharge_time);
        let bullets_bar = bar!(self.state.bullets as f64, self.config.bullet_stock as f64);
        // Closure in `draw_2d` requires unique access to `self`,
        // so we use RefCell to hack it.
        let mut glyphs = self.glyphs.borrow_mut();
        let fps = format!("{:.3}", self.state.fps);
        let lines = self.world.render(&self.camera);
        self.window.draw_2d(e, |c, g| {
            clear(BLACK.into(), g);
            for (l, color) in lines {
                line(color.into(), 1., convert(l), c.transform, g);
            }
            rectangle(BLUE.alpha(0.4).into(), jump_bar, c.transform, g);
            rectangle(RED.alpha(0.4).into(), recharge_bar, c.transform, g);
            rectangle(GREEN.alpha(0.4).into(), bullets_bar, c.transform, g);
            text(WHITE.into(), 10, &fps, glyphs.deref_mut(), c.transform.trans(0., 10.), g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            let ellipse = self.ellipse.borrow();
            self.window.draw_2d(e, |c, g| {
                ellipse.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED.into(), [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    // `dt` stands for delta, duration since the last update
    fn update(&mut self, dt: f64) {
        // Re-calculate delta according to fps
        let dt = if self.state.fps != 0. { 1./self.state.fps}
        else { dt };
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += ::rnd(self.config.spawn_time);
        }
        match self.state.turn {
            Turn::Left => self.world.player.turn_left(dt),
            Turn::Right => self.world.player.turn_right(dt),
            Turn::None => (),
        }
        // Update objects in the world
        self.world.update(dt, self.state.game_speed);
        // Validate things like object's boundary, bullets and boxes
        // collisions.
        self.world.validate();
        // Update camera's location
        self.camera.eye += self.world.player.position - old;
        // Check for player's collision with bot
        if self.world.bots.iter().any(|x| self.world.player.crashed(&x.car)) {
            self.state.ended = true;
        }
    }
}

fn convert(x: [Vector2<f64>; 2]) -> [f64; 4] {
    [x[0].x, x[0].y, x[1].x, x[1].y]
}
<commit_msg>Fix bug<commit_after>use world::World;
use piston_window::*;
use camera::Camera;
use cgmath::{Vector2, vec3};
use cgmath::prelude::*;
use color::*;
use car::*;
use piston_window::Ellipse;
use bot::BoxRules;
use std::cell::RefCell;
use std::ops::DerefMut;
use std::time::Instant;

// `Game` contains every things to run the game
pub struct Game {
    config: GameConfig,
    world: World, // All objects in the game
    window: PistonWindow,
    bot_rules: BoxRules, // Rules to create a new bot
    camera: Camera, // Camera for rendering
    state: State, // Current state of game
    // Wrap these caches in `RefCell` to allow interior mutability
    glyphs: RefCell<Glyphs>, // Font cache
    ellipse: RefCell<Ellipse>, // Model to draw a circle
}

struct State {
    pub turn: Turn, // Presents movement of player
    pub sprint: bool, // Player is speeding-up or not
    pub spawn: f64, // Count down time to spawn a new bot
    pub ended: bool, // Game is over or not
    pub game_speed: f64, // Game speed in addition to player's speed
    pub jump_timeout: f64, // Count down to allow the next jump
    pub rotate_cam: bool, // Allow rotation of camera or not
    pub bullets: i64, // The number of bullets left
    pub recharge: f64, // Bullets recharge time
    pub fps: f64, // Real fps of game
    pub last_frame: Instant, // Moment of the last draw
}

pub enum Turn { Left, Right, None, }

// Configurable game's contansts.
// A tuple presents a range of something.
#[derive(Serialize, Deserialize, Clone)]
pub struct GameConfig {
    pub title: String,
    pub screen_size: ::Pixel,
    pub ups: u64, // Update per second
    pub max_fps: u64,
    pub tunel_size: [f64; 3],
    pub player_size: [f64; 3],
    pub player_speed: (f64, f64), // min and max player speed
    pub player_turn_speed: f64,
    pub bot_size: [(f64, f64); 3], // Range of bot's size
    pub bot_speed: (f64, f64),
    pub bot_turn_speed: (f64, f64),
    pub divider_size: [f64; 2],
    pub camera_height: f64, // Height of camera (from player)
    pub camera_distance: f64, // Distance from camera to player
    pub decor_distance: f64, // Distance between each decoration
    pub sprint_factor: f64,
    pub spawn_time: (f64, f64),
    pub game_sprint: f64, // The increase of game_speed
    pub game_max_speed: f64,
    pub player_jump_v: f64,
    pub player_jump_a: f64,
    pub jump_turn_decrease: f64,
    pub jump_timeout: f64,
    pub mouse_speed: f64,
    pub trueshot_distance: f64,
    pub bullet_stock: i64, // Number of bullets
    pub recharge_time: f64,
    pub bullet_len: f64,
    pub bullet_speed: f64,
    pub zoom_in: bool, // If true, zoom-in while on stare mode
}

impl Game {
    pub fn new(config: GameConfig) -> Game {
        let mut window: PistonWindow = WindowSettings::new(
            config.title.clone(), [config.screen_size.w, config.screen_size.h])
            .exit_on_esc(true).build()
            .expect("Cannot create window.");
        window.set_ups(config.ups);
        window.set_max_fps(config.max_fps);
        window.set_capture_cursor(true);
        let glyphs = Glyphs::new("resources/Ubuntu-R.ttf", window.factory.clone())
            .expect("Unable to load font.");
        let bot_rules = BoxRules {
            size: config.bot_size,
            position: [(0., config.tunel_size[0]), (0., 0.), (config.tunel_size[2], config.tunel_size[2])],
            speed: config.bot_speed,
            turn_speed: config.bot_turn_speed,
            color: vec![RED, ORANGE, VIOLET, GREEN, PALE],
            jump_turn_decrease: config.jump_turn_decrease,
        };
        let world = World::new(&config);
        let camera = Game::new_camera(&config, &world.player);
        let state = State {
            turn: Turn::None,
            sprint: false,
            spawn: 0.,
            ended: false,
            game_speed: 0.,
            jump_timeout: 0.,
            rotate_cam: false,
            bullets: config.bullet_stock,
            recharge: 0.,
            fps: 0.,
            last_frame: Instant::now(),
        };
        let ellipse = Ellipse {
            color: BLACK.alpha(0.).into(),
            border: Some(ellipse::Border {
                color: RED.alpha(0.5).into(),
                radius: 1.,
            }),
            resolution: 16,
        };

        Game {
            config: config,
            world: world,
            window: window,
            bot_rules: bot_rules,
            camera: camera,
            state: state,
            glyphs: RefCell::new(glyphs),
            ellipse: RefCell::new(ellipse),
        }
    }

    fn new_camera<T: Car>(config: &GameConfig, player: &T) -> Camera {
        Camera::new(
            config.screen_size.clone(),
            vec3(0., config.camera_height, -config.camera_distance) + player.pos()
        )
    }
    // Re-calculate fps
    fn update_fps(&mut self) {
        let d = self.state.last_frame.elapsed();
        self.state.last_frame = Instant::now();
        self.state.fps = 1. / (d.as_secs() as f64 + 1e-9*d.subsec_nanos() as f64);
    }

    pub fn run(&mut self) {
        while let Some(e) = self.window.next() {
            match e {
                Input::Press(key) => self.press(key),
                Input::Release(key) => self.release(key),
                Input::Render(_) => {
                    self.update_fps();
                    self.draw(&e);
                },
                Input::Update(args) => self.update(args.dt),
                Input::Move(Motion::MouseRelative(a, b)) => self.mouse_move(a as f64, b as f64),
                _ => {}
            }
            if self.state.ended {
                break;
            }
        }
    }
    fn mouse_move(&mut self, x: f64, y: f64) {
        if self.state.rotate_cam {
            self.camera.rotate(x*self.config.mouse_speed, y*self.config.mouse_speed, self.world.player.position);
        }
    }
    fn press(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => self.state.turn = Turn::Left,
            Button::Keyboard(Key::D) => self.state.turn = Turn::Right,
            Button::Keyboard(Key::W) => self.state.sprint = true,
            Button::Keyboard(Key::Space) => if self.state.jump_timeout <= 0. {
                self.state.jump_timeout = self.config.jump_timeout;
                self.world.player.jump();
            },
            Button::Mouse(MouseButton::Right) => {
                if self.config.zoom_in {
                    self.camera.zoom_in();
                }
                self.state.rotate_cam = true;
            },
            Button::Mouse(MouseButton::Left) => if self.state.rotate_cam && self.state.bullets > 0 {
                let mut pos = self.world.player.position;
                pos.y += self.world.player.size.y;
                let mut d = vec3(0., 0., self.config.trueshot_distance + self.config.camera_distance);
                d = self.camera.c * d.magnitude2() / d.dot(self.camera.c);
                d = self.camera.eye + d - pos;
                d = d * self.config.bullet_speed / d.magnitude();
                self.world.add_bullet(pos, d, self.config.bullet_len);
                self.state.bullets -= 1;
                if self.state.bullets <= 0 {
                    self.state.recharge = self.config.recharge_time;
                }
            },
            _ => (),
        }
    }
    fn release(&mut self, key: Button) {
        match key {
            Button::Keyboard(Key::A) => if let Turn::Left = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::D) => if let Turn::Right = self.state.turn {
                self.state.turn = Turn::None;
            },
            Button::Keyboard(Key::W) => self.state.sprint = false,
            Button::Mouse(MouseButton::Right) => {
                self.state.rotate_cam = false;
                self.camera = Game::new_camera(&self.config, &self.world.player);
            },
            _ => (),
        }
    }
    fn draw(&mut self, e: &Input) {
        // Return a horizontal bar
        macro_rules! bar {
            ($curr: expr, $full: expr) => {
                [0.,
                self.config.screen_size.h as f64 - 20.,
                self.config.screen_size.w as f64/2.*$curr/$full,
                self.config.screen_size.h as f64,]
            };
        }
        let jump_bar = bar!(self.state.jump_timeout, self.config.jump_timeout);
        let recharge_bar = bar!(self.state.recharge, self.config.recharge_time);
        let bullets_bar = bar!(self.state.bullets as f64, self.config.bullet_stock as f64);
        // Closure in `draw_2d` requires unique access to `self`,
        // so we use RefCell to hack it.
        let mut glyphs = self.glyphs.borrow_mut();
        let fps = format!("{:.3}", self.state.fps);
        let lines = self.world.render(&self.camera);
        self.window.draw_2d(e, |c, g| {
            clear(BLACK.into(), g);
            for (l, color) in lines {
                line(color.into(), 1., convert(l), c.transform, g);
            }
            rectangle(BLUE.alpha(0.4).into(), jump_bar, c.transform, g);
            rectangle(RED.alpha(0.4).into(), recharge_bar, c.transform, g);
            rectangle(GREEN.alpha(0.4).into(), bullets_bar, c.transform, g);
            text(WHITE.into(), 10, &fps, glyphs.deref_mut(), c.transform.trans(0., 10.), g);
        });

        if self.state.rotate_cam {
            let w = 20.;
            let x = self.config.screen_size.w as f64 /2. - w/2.;
            let y = self.config.screen_size.h as f64 /2. - w/2.;
            let ellipse = self.ellipse.borrow();
            self.window.draw_2d(e, |c, g| {
                ellipse.draw([x, y, w, w], &c.draw_state, c.transform, g);
                rectangle(RED.into(), [x+w/2.-1., y+w/2.-1., 2., 2.], c.transform, g);
            });
        }

    }
    // `dt` stands for delta, duration since the last update
    fn update(&mut self, dt: f64) {
        // Re-calculate delta according to fps
        let dt = if self.state.fps != 0. { 1./self.state.fps}
        else { dt };
        let old = self.world.player.position;
        if self.state.bullets <= 0 {
            self.state.recharge -= dt;
            if self.state.recharge < 0. {
                self.state.bullets = self.config.bullet_stock;
            }
        }
        self.state.jump_timeout -= dt;
        if self.state.game_speed < self.config.game_max_speed {
            self.state.game_speed += dt*self.config.game_sprint;
        }
        if self.state.sprint {
            if self.world.player.speed < self.config.player_speed.1 {
                self.world.player.speed += dt*self.config.sprint_factor;
            }
        } else if self.world.player.speed > self.config.player_speed.0 {
            self.world.player.speed -= dt*self.config.sprint_factor;
        }
        self.state.spawn -= dt;
        if self.state.spawn < 0. {
            self.world.add_bot(&self.bot_rules);
            self.state.spawn += ::rnd(self.config.spawn_time);
        }
        match self.state.turn {
            Turn::Left => self.world.player.turn_left(dt),
            Turn::Right => self.world.player.turn_right(dt),
            Turn::None => (),
        }
        // Update objects in the world
        self.world.update(dt, self.state.game_speed);
        // Validate things like object's boundary, bullets and boxes
        // collisions.
        self.world.validate();
        // Update camera's location
        self.camera.eye += self.world.player.position - old;
        // Check for player's collision with bot
        if self.world.bots.iter().any(|x| self.world.player.crashed(&x.car)) {
            self.state.ended = true;
        }
    }
}

fn convert(x: [Vector2<f64>; 2]) -> [f64; 4] {
    [x[0].x, x[0].y, x[1].x, x[1].y]
}
<|endoftext|>