<commit_before>use std::num::Float;
use std::sync::{Mutex, Arc};
use std::sync::atomic::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    pub fn rate(&self) -> f64 {
        self.value
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();

        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        EWMASnapshot{
            value: self.rate()
        }
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }

    // construct new by alpha
    pub fn new_by_alpha(alpha: f64) -> EWMA {
        EWMA{
            uncounted: AtomicUint::new(0u),
            alpha: alpha,
            rate: Mutex::new(0f64),
            init: false
        }
    }

    // constructs a new EWMA for a n-minute moving average.
    pub fn new(rate: f64) -> EWMA {
        let i: f64 = -5.0f64 / 60.0f64 / rate;
        EWMA::new_by_alpha(1f64 - i.exp())
    }
}

#[cfg(test)]
mod test {
    use ewma::EWMA;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let mut e = EWMA::new(1f64);
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let mut e = EWMA::new(5f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let mut e = EWMA::new(15f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}<commit_msg>Fix unused import warning<commit_after>use std::num::Float;
use std::sync::Mutex;
use std::sync::atomic::{AtomicUint, SeqCst};

pub struct EWMA {
    pub uncounted: AtomicUint, // This tracks uncounted events
    alpha: f64,
    rate: Mutex<f64>,
    init: bool,
}

pub struct EWMASnapshot {
    value: f64
}

impl EWMASnapshot {
    pub fn rate(&self) -> f64 {
        self.value
    }
}

impl EWMA {
    pub fn rate(&self) -> f64 {
        let r = self.rate.lock();

        *r * (1e9 as f64)
    }

    pub fn snapshot(&self) -> EWMASnapshot {
        EWMASnapshot{
            value: self.rate()
        }
    }

    pub fn tick(&mut self) {
        let counter: uint = self.uncounted.load(SeqCst);

        self.uncounted.fetch_sub(counter, SeqCst); // Broken atm

        let mut rate = self.rate.lock();
        let i_rate = (counter as f64) / (5e9);

        if self.init {
            *rate += self.alpha * (i_rate - *rate);
        } else {
            self.init = true;
            *rate = i_rate;
        }

        rate.cond.signal();
    }

    pub fn update(&self, n: uint) {
        self.uncounted.fetch_add(n, SeqCst);
    }

    // construct new by alpha
    pub fn new_by_alpha(alpha: f64) -> EWMA {
        EWMA{
            uncounted: AtomicUint::new(0u),
            alpha: alpha,
            rate: Mutex::new(0f64),
            init: false
        }
    }

    // constructs a new EWMA for a n-minute moving average.
    pub fn new(rate: f64) -> EWMA {
        let i: f64 = -5.0f64 / 60.0f64 / rate;
        EWMA::new_by_alpha(1f64 - i.exp())
    }
}

#[cfg(test)]
mod test {
    use ewma::EWMA;
    use std::num::Float;

    // Tick a minute
    fn elapse_minute(e: &mut EWMA) {
        for i in range(0i, 12i) {
            e.tick();
        }
    }

    // Returns whether the rate() is within 0.0001 of expected after ticking a minute
    fn within(e: &mut EWMA, expected: f64) -> bool {
        elapse_minute(e);
        let r: f64 = e.rate();
        (r - expected).abs() < 0.0001
    }

    #[test]
    fn ewma1() {
        let mut e = EWMA::new(1f64);
        e.update(3u);
        e.tick();

        let mut r: f64;

        // initial
        r = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.22072766470286553f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.08120116994196772f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.029872241020718428f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.01098938333324054f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.004042768199451294f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.0014872513059998212f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.0005471291793327122f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.00020127757674150815f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 7.404588245200814e-05f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 2.7239957857491083e-05f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 1.0021020474147462e-05f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 3.6865274119969525e-06f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 1.3561976441886433e-06f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 4.989172314621449e-07f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 1.8354139230109722e-07f64), true);
    }

    #[test]
    fn ewma5() {
        let mut e = EWMA::new(5f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.49123845184678905f64), true);

                // 2 minute
        assert_eq!(within(&mut e, 0.4021920276213837f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.32928698165641596f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.269597378470333f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.2207276647028654f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.18071652714732128f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.14795817836496392f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.12113791079679326f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.09917933293295193f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.08120116994196763f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.06648189501740036), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.05443077197364752f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.04456414692860035f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.03648603757513079f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.0298722410207183831020718428f64), true);
    }

        #[test]
    fn ewma15() {
        let mut e = EWMA::new(15f64);
        e.update(3u);
        e.tick();

        let r: f64 = e.rate();
        assert_eq!(r, 0.6f64);

        // 1 minute
        assert_eq!(within(&mut e, 0.5613041910189706f64), true);

        // 2 minute
        assert_eq!(within(&mut e, 0.5251039914257684f64), true);

        // 3 minute
        assert_eq!(within(&mut e, 0.4912384518467888184678905f64), true);

        // 4 minute
        assert_eq!(within(&mut e, 0.459557003018789f64), true);

        // 5 minute
        assert_eq!(within(&mut e, 0.4299187863442732f64), true);

        // 6 minute
        assert_eq!(within(&mut e, 0.4021920276213831f64), true);

        // 7 minute
        assert_eq!(within(&mut e, 0.37625345116383313f64), true);

        // 8 minute
        assert_eq!(within(&mut e, 0.3519877317060185f64), true);

        // 9 minute
        assert_eq!(within(&mut e, 0.3292869816564153165641596f64), true);

        // 10 minute
        assert_eq!(within(&mut e, 0.3080502714195546f64), true);

        // 11 minute
        assert_eq!(within(&mut e, 0.2881831806538789f64), true);

        // 12 minute
        assert_eq!(within(&mut e, 0.26959737847033216f64), true);

        // 13 minute
        assert_eq!(within(&mut e, 0.2522102307052083f64), true);

        // 14 minute
        assert_eq!(within(&mut e, 0.23594443252115815f64), true);

        // 15 minute
        assert_eq!(within(&mut e, 0.2207276647028646247028654470286553f64), true);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ffi::CStr;
use std::rc::Rc;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };

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

bitflags! {
    pub struct 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;
    }
}

bitflags! {
    pub struct StyleFlag: ffi::FT_Long {
        const BOLD   = ::ffi::FT_STYLE_FLAG_BOLD;
        const ITALIC = ::ffi::FT_STYLE_FLAG_ITALIC;
    }
}

#[derive(Eq, PartialEq, Hash)]
pub struct Face {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    bytes: Option<Rc<Vec<u8>>>
}

impl Clone for Face {
    fn clone(&self) -> Self {
        let err = unsafe {
            ffi::FT_Reference_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference library");
        }
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference face");
        }
        Face {
            library_raw: self.library_raw,
            raw: self.raw,
            glyph: self.glyph,
            bytes: self.bytes.clone()
        }
    }
}

impl Face {
    pub unsafe fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face, bytes: Option<Rc<Vec<u8>>>) -> Self {
        ffi::FT_Reference_Library(library_raw);
        Face {
            library_raw,
            raw,
            glyph: GlyphSlot::from_raw(library_raw, (*raw).glyph),
            bytes,
        }
    }

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

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

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        let err = unsafe {
            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(err.into())
        }
    }

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

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

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

    pub fn set_transform(&self, matrix: &mut Matrix, delta: &mut 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 = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };
        if err == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(err.into())
        }
    }

    // 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 raw_mut(&mut self) -> &mut ffi::FT_FaceRec {
        unsafe {
            &mut *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 em_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).units_per_EM as i16
        }
    }

    #[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
        }
    }

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

    pub fn family_name(&self) -> Option<String> {
        let family_name = unsafe { (*self.raw).family_name };

        if family_name.is_null() {
            None
        } else {
            let family_name = unsafe {
                CStr::from_ptr(family_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {
        let style_name = unsafe { (*self.raw).style_name };

        if style_name.is_null() {
            None
        } else {
            let style_name = unsafe {
                CStr::from_ptr(style_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(style_name).ok()
        }
    }

    pub fn style_flags(&self) -> StyleFlag {
        let style_flags = unsafe { (*self.raw).style_flags };
        StyleFlag::from_bits_truncate(style_flags)
    }

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

    pub fn postscript_name(&self) -> Option<String> {
        let face_name = unsafe { ffi::FT_Get_Postscript_Name(self.raw) };
        if face_name.is_null() {
            None
        } else {
            let face_name = unsafe {
                CStr::from_ptr(face_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(face_name).ok()
        }
    }
}

impl fmt::Debug for Face {
    fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_owned());
        form.write_str("Font Face: ")?;
        form.write_str(&name[..])
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        let err = unsafe {
            ffi::FT_Done_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop face");
        }
        let err = unsafe {
            ffi::FT_Done_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop library")
        }
        self.bytes = None;
    }
}
<commit_msg>Expose FT_FaceRec::num_glyphs<commit_after>use std::fmt;
use std::ffi::CStr;
use std::rc::Rc;
use { ffi, FtResult, GlyphSlot, Matrix, Vector };

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

bitflags! {
    pub struct 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;
    }
}

bitflags! {
    pub struct StyleFlag: ffi::FT_Long {
        const BOLD   = ::ffi::FT_STYLE_FLAG_BOLD;
        const ITALIC = ::ffi::FT_STYLE_FLAG_ITALIC;
    }
}

#[derive(Eq, PartialEq, Hash)]
pub struct Face {
    library_raw: ffi::FT_Library,
    raw: ffi::FT_Face,
    glyph: GlyphSlot,
    bytes: Option<Rc<Vec<u8>>>
}

impl Clone for Face {
    fn clone(&self) -> Self {
        let err = unsafe {
            ffi::FT_Reference_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference library");
        }
        let err = unsafe {
            ffi::FT_Reference_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to reference face");
        }
        Face {
            library_raw: self.library_raw,
            raw: self.raw,
            glyph: self.glyph,
            bytes: self.bytes.clone()
        }
    }
}

impl Face {
    pub unsafe fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face, bytes: Option<Rc<Vec<u8>>>) -> Self {
        ffi::FT_Reference_Library(library_raw);
        Face {
            library_raw,
            raw,
            glyph: GlyphSlot::from_raw(library_raw, (*raw).glyph),
            bytes,
        }
    }

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

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

    pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
                         vert_resolution: u32) -> FtResult<()> {
        let err = unsafe {
            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(err.into())
        }
    }

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

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

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

    pub fn set_transform(&self, matrix: &mut Matrix, delta: &mut 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 = unsafe {
            ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
                                kern_mode as u32, &mut vec)
        };
        if err == ffi::FT_Err_Ok {
            Ok(vec)
        } else {
            Err(err.into())
        }
    }

    // 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 raw_mut(&mut self) -> &mut ffi::FT_FaceRec {
        unsafe {
            &mut *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 em_size(&self) -> ffi::FT_Short {
        unsafe {
            (*self.raw).units_per_EM as i16
        }
    }

    #[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
        }
    }

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

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

    pub fn family_name(&self) -> Option<String> {
        let family_name = unsafe { (*self.raw).family_name };

        if family_name.is_null() {
            None
        } else {
            let family_name = unsafe {
                CStr::from_ptr(family_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(family_name).ok()
        }
    }

    pub fn style_name(&self) -> Option<String> {
        let style_name = unsafe { (*self.raw).style_name };

        if style_name.is_null() {
            None
        } else {
            let style_name = unsafe {
                CStr::from_ptr(style_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(style_name).ok()
        }
    }

    pub fn style_flags(&self) -> StyleFlag {
        let style_flags = unsafe { (*self.raw).style_flags };
        StyleFlag::from_bits_truncate(style_flags)
    }

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

    pub fn postscript_name(&self) -> Option<String> {
        let face_name = unsafe { ffi::FT_Get_Postscript_Name(self.raw) };
        if face_name.is_null() {
            None
        } else {
            let face_name = unsafe {
                CStr::from_ptr(face_name as *const _).to_bytes().to_vec()
            };
            String::from_utf8(face_name).ok()
        }
    }
}

impl fmt::Debug for Face {
    fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
        let name = self.style_name().unwrap_or("[unknown name]".to_owned());
        form.write_str("Font Face: ")?;
        form.write_str(&name[..])
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        let err = unsafe {
            ffi::FT_Done_Face(self.raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop face");
        }
        let err = unsafe {
            ffi::FT_Done_Library(self.library_raw)
        };
        if err != ffi::FT_Err_Ok {
            panic!("Failed to drop library")
        }
        self.bytes = None;
    }
}
<|endoftext|>


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

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType};
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use data_provider::CGDataProvider;
use geometry::CGRect;

use foreign_types::ForeignType;

use libc::{self, c_int, size_t};

pub type CGGlyph = libc::c_ushort;

foreign_type! {
    #[doc(hidden)]
    type CType = ::sys::CGFont;
    fn drop = |p| CFRelease(p as *mut _);
    fn clone = |p| CFRetain(p as *const _) as *mut _;
    pub struct CGFont;
    pub struct CGFontRef;
}

unsafe impl Send for CGFont {}
unsafe impl Sync for CGFont {}

impl CGFont {
    pub fn type_id() -> CFTypeID {
        unsafe {
            CGFontGetTypeID()
        }
    }

    pub fn from_data_provider(provider: CGDataProvider) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateWithDataProvider(provider.as_ptr());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn from_name(name: &CFString) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateWithFontName(name.as_concrete_TypeRef());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn create_copy_from_variations(&self, vars: &CFDictionary) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateCopyWithVariations(self.as_ptr(),
            vars.as_concrete_TypeRef());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn postscript_name(&self) -> CFString {
        unsafe {
            let string_ref = CGFontCopyPostScriptName(self.as_ptr());
            TCFType::wrap_under_create_rule(string_ref)
        }
    }

    pub fn get_glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool {
        unsafe {
            assert!(bboxes.len() >= glyphs.len());
            CGFontGetGlyphBBoxes(self.as_ptr(),
                                 glyphs.as_ptr(),
                                 glyphs.len(),
                                 bboxes.as_mut_ptr())
        }
    }

    pub fn get_glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool {
        unsafe {
            assert!(advances.len() >= glyphs.len());
            CGFontGetGlyphAdvances(self.as_ptr(),
                                   glyphs.as_ptr(),
                                   glyphs.len(),
                                   advances.as_mut_ptr())
        }
    }

    pub fn get_units_per_em(&self) -> c_int {
        unsafe {
            CGFontGetUnitsPerEm(self.as_ptr())
        }
    }
}

#[link(name = "CoreGraphics", kind = "framework")]
extern {
    // TODO: basically nothing has bindings (even commented-out) besides what we use.
    fn CGFontCreateWithDataProvider(provider: ::sys::CGDataProviderRef) -> ::sys::CGFontRef;
    fn CGFontCreateWithFontName(name: CFStringRef) -> ::sys::CGFontRef;
    fn CGFontCreateCopyWithVariations(font: ::sys::CGFontRef, vars: CFDictionaryRef) -> ::sys::CGFontRef;
    fn CGFontGetTypeID() -> CFTypeID;

    fn CGFontCopyPostScriptName(font: ::sys::CGFontRef) -> CFStringRef;

    // These do the same thing as CFRetain/CFRelease, except
    // gracefully handle a NULL argument. We don't use them.
    //fn CGFontRetain(font: ::sys::CGFontRef);
    //fn CGFontRelease(font: ::sys::CGFontRef);

    fn CGFontGetGlyphBBoxes(font: ::sys::CGFontRef,
                            glyphs: *const CGGlyph,
                            count: size_t,
                            bboxes: *mut CGRect)
                            -> bool;
    fn CGFontGetGlyphAdvances(font: ::sys::CGFontRef,
                              glyphs: *const CGGlyph,
                              count: size_t,
                              advances: *mut c_int)
                              -> bool;
    fn CGFontGetUnitsPerEm(font: ::sys::CGFontRef) -> c_int;
}
<commit_msg>spaces alignment<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType};
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use data_provider::CGDataProvider;
use geometry::CGRect;

use foreign_types::ForeignType;

use libc::{self, c_int, size_t};

pub type CGGlyph = libc::c_ushort;

foreign_type! {
    #[doc(hidden)]
    type CType = ::sys::CGFont;
    fn drop = |p| CFRelease(p as *mut _);
    fn clone = |p| CFRetain(p as *const _) as *mut _;
    pub struct CGFont;
    pub struct CGFontRef;
}

unsafe impl Send for CGFont {}
unsafe impl Sync for CGFont {}

impl CGFont {
    pub fn type_id() -> CFTypeID {
        unsafe {
            CGFontGetTypeID()
        }
    }

    pub fn from_data_provider(provider: CGDataProvider) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateWithDataProvider(provider.as_ptr());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn from_name(name: &CFString) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateWithFontName(name.as_concrete_TypeRef());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn create_copy_from_variations(&self, vars: &CFDictionary) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateCopyWithVariations(self.as_ptr(),
                                                          vars.as_concrete_TypeRef());
            if !font_ref.is_null() {
                Ok(CGFont::from_ptr(font_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn postscript_name(&self) -> CFString {
        unsafe {
            let string_ref = CGFontCopyPostScriptName(self.as_ptr());
            TCFType::wrap_under_create_rule(string_ref)
        }
    }

    pub fn get_glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool {
        unsafe {
            assert!(bboxes.len() >= glyphs.len());
            CGFontGetGlyphBBoxes(self.as_ptr(),
                                 glyphs.as_ptr(),
                                 glyphs.len(),
                                 bboxes.as_mut_ptr())
        }
    }

    pub fn get_glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool {
        unsafe {
            assert!(advances.len() >= glyphs.len());
            CGFontGetGlyphAdvances(self.as_ptr(),
                                   glyphs.as_ptr(),
                                   glyphs.len(),
                                   advances.as_mut_ptr())
        }
    }

    pub fn get_units_per_em(&self) -> c_int {
        unsafe {
            CGFontGetUnitsPerEm(self.as_ptr())
        }
    }
}

#[link(name = "CoreGraphics", kind = "framework")]
extern {
    // TODO: basically nothing has bindings (even commented-out) besides what we use.
    fn CGFontCreateWithDataProvider(provider: ::sys::CGDataProviderRef) -> ::sys::CGFontRef;
    fn CGFontCreateWithFontName(name: CFStringRef) -> ::sys::CGFontRef;
    fn CGFontCreateCopyWithVariations(font: ::sys::CGFontRef, vars: CFDictionaryRef) -> ::sys::CGFontRef;
    fn CGFontGetTypeID() -> CFTypeID;

    fn CGFontCopyPostScriptName(font: ::sys::CGFontRef) -> CFStringRef;

    // These do the same thing as CFRetain/CFRelease, except
    // gracefully handle a NULL argument. We don't use them.
    //fn CGFontRetain(font: ::sys::CGFontRef);
    //fn CGFontRelease(font: ::sys::CGFontRef);

    fn CGFontGetGlyphBBoxes(font: ::sys::CGFontRef,
                            glyphs: *const CGGlyph,
                            count: size_t,
                            bboxes: *mut CGRect)
                            -> bool;
    fn CGFontGetGlyphAdvances(font: ::sys::CGFontRef,
                              glyphs: *const CGGlyph,
                              count: size_t,
                              advances: *mut c_int)
                              -> bool;
    fn CGFontGetUnitsPerEm(font: ::sys::CGFontRef) -> c_int;
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use shared::*;

fn make_glyph(v: [&'static str; 7]) -> Glyph {
    let width = v[0].len();
    let mut glyph = vec![];
    for _ in 0..width {
        glyph.push(EMPTY_COLUMN);
    }
    for y in 0..v.len() {
        let row = v[y];
        for x in 0..row.len() {
            let c = row.chars().nth(x).unwrap();
            glyph[x][y] = if c == ' ' { 0x00 } else { 0x0F };
        }
    }
    glyph
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn font() -> HashMap<char, Glyph> {
    let mut glyphs = HashMap::new();
    glyphs.insert(' ', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('.', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x"]));
    glyphs.insert('!', make_glyph([
                  " " ,
                  "x",
                  "x",
                  "x",
                  "x",
                  " ",
                  "x"]));
    glyphs.insert(',', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(';', make_glyph([
                  " " ,
                  " ",
                  " ",
                  "x",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(':', make_glyph([
                  " " ,
                  " ",
                  "x",
                  " ",
                  " ",
                  "x",
                  " "]));
    glyphs.insert('\'', make_glyph([
                  "x" ,
                  "x",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('"', make_glyph([
                  "x x" ,
                  "x x",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('°', make_glyph([
                  "xxx" ,
                  "x x",
                  "xxx",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('-', make_glyph([
                  "   " ,
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('_', make_glyph([
                  "   " ,
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "xxx"]));
    glyphs.insert('+', make_glyph([
                  "   " ,
                  "   ",
                  " x ",
                  "xxx",
                  " x ",
                  "   ",
                  "   "]));
    glyphs.insert('=', make_glyph([
                  "   " ,
                  "   ",
                  "xxx",
                  "   ",
                  "xxx",
                  "   ",
                  "   "]));
    glyphs.insert('0', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x xx",
                  "xx x",
                  "x  x",
                  " xx "]));
    glyphs.insert('1', make_glyph([
                  "   " ,
                  " x ",
                  "xx ",
                  " x ",
                  " x ",
                  " x ",
                  "xxx"]));
    glyphs.insert('2', make_glyph([
                  "    " ,
                  "xxx ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('3', make_glyph([
                  "    " ,
                  "xxx ",
                  "   x",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('4', make_glyph([
                  "    " ,
                  "   x",
                  "  x ",
                  " x  ",
                  "x  x",
                  "xxxx",
                  "   x"]));
    glyphs.insert('5', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('6', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('7', make_glyph([
                  "    " ,
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "x   "]));
    glyphs.insert('8', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  " xx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('9', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  " xxx",
                  "   x",
                  "   x",
                  " xx "]));
    glyphs.insert('A', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x"]));
    glyphs.insert('B', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('C', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "x   ",
                  "x   ",
                  "x   ",
                  " xxx"]));
    glyphs.insert('D', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('E', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('F', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('G', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "x   ",
                  "x xx",
                  "x  x",
                  " xxx"]));
    glyphs.insert('H', make_glyph([
                  "    " ,
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('I', make_glyph([
                  " " ,
                  "x",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x"]));
    glyphs.insert('J', make_glyph([
                  "    " ,
                  "   x",
                  "   x",
                  "   x",
                  "   x",
                  "x  x",
                  " xx "]));
    glyphs.insert('K', make_glyph([
                  "    " ,
                  "x  x",
                  "x x ",
                  "xx  ",
                  "x x ",
                  "x  x",
                  "x  x"]));
    glyphs.insert('L', make_glyph([
                  "   " ,
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "xxx"]));
    glyphs.insert('M', make_glyph([
                  "     " ,
                  "x   x",
                  "xx xx",
                  "x x x",
                  "x   x",
                  "x   x",
                  "x   x"]));
    glyphs.insert('N', make_glyph([
                  "    " ,
                  "x  x",
                  "xx x",
                  "x xx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('O', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('P', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('Q', make_glyph([
                  "     " ,
                  " xx  ",
                  "x  x ",
                  "x  x ",
                  "x  x ",
                  "x xx ",
                  " xx x"]));
    glyphs.insert('R', make_glyph([
                  "     " ,
                  "xxx  ",
                  "x  x ",
                  "xxx  ",
                  "x  x ",
                  "x  x ",
                  "x  x "]));
    glyphs.insert('S', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('T', make_glyph([
                  "     " ,
                  "xxxxx",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('U', make_glyph([
                  "    " ,
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('V', make_glyph([
                  "     " ,
                  "x   x",
                  "x   x",
                  "x   x",
                  "x   x",
                  " x x ",
                  "  x  "]));
    glyphs.insert('W', make_glyph([
                  "     " ,
                  "x   x",
                  "x   x",
                  "x   x",
                  "x x x",
                  "x x x",
                  " x x "]));
    glyphs.insert('X', make_glyph([
                  "     " ,
                  "x   x",
                  " x x ",
                  "  x  ",
                  " x x ",
                  "x   x",
                  "x   x"]));
    glyphs.insert('Y', make_glyph([
                  "     " ,
                  "x   x",
                  " x x ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('Z', make_glyph([
                  "    " ,
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs
}
<commit_msg>Add #, /, and \ to the font<commit_after>use std::collections::HashMap;

use shared::*;

fn make_glyph(v: [&'static str; 7]) -> Glyph {
    let width = v[0].len();
    let mut glyph = vec![];
    for _ in 0..width {
        glyph.push(EMPTY_COLUMN);
    }
    for y in 0..v.len() {
        let row = v[y];
        for x in 0..row.len() {
            let c = row.chars().nth(x).unwrap();
            glyph[x][y] = if c == ' ' { 0x00 } else { 0x0F };
        }
    }
    glyph
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn font() -> HashMap<char, Glyph> {
    let mut glyphs = HashMap::new();
    glyphs.insert(' ', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('.', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  " ",
                  "x"]));
    glyphs.insert('!', make_glyph([
                  " " ,
                  "x",
                  "x",
                  "x",
                  "x",
                  " ",
                  "x"]));
    glyphs.insert(',', make_glyph([
                  " " ,
                  " ",
                  " ",
                  " ",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(';', make_glyph([
                  " " ,
                  " ",
                  " ",
                  "x",
                  " ",
                  "x",
                  "x"]));
    glyphs.insert(':', make_glyph([
                  " " ,
                  " ",
                  "x",
                  " ",
                  " ",
                  "x",
                  " "]));
    glyphs.insert('\'', make_glyph([
                  "x" ,
                  "x",
                  " ",
                  " ",
                  " ",
                  " ",
                  " "]));
    glyphs.insert('"', make_glyph([
                  "x x" ,
                  "x x",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('\\', make_glyph([
                  "   ",
                  "x  ",
                  "x  ",
                  " x ",
                  " x ",
                  "  x",
                  "  x"]));
    glyphs.insert('/', make_glyph([
                  "   ",
                  "  x",
                  "  x",
                  " x ",
                  " x ",
                  "x  ",
                  "x  "]));
    glyphs.insert('°', make_glyph([
                  "xxx" ,
                  "x x",
                  "xxx",
                  "   ",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('#', make_glyph([
                  "     " ,
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "xxxxx",
                  " x x ",
                  "     "]));
    glyphs.insert('-', make_glyph([
                  "   " ,
                  "   ",
                  "   ",
                  "xxx",
                  "   ",
                  "   ",
                  "   "]));
    glyphs.insert('_', make_glyph([
                  "   " ,
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "   ",
                  "xxx"]));
    glyphs.insert('+', make_glyph([
                  "   " ,
                  "   ",
                  " x ",
                  "xxx",
                  " x ",
                  "   ",
                  "   "]));
    glyphs.insert('=', make_glyph([
                  "   " ,
                  "   ",
                  "xxx",
                  "   ",
                  "xxx",
                  "   ",
                  "   "]));
    glyphs.insert('0', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x xx",
                  "xx x",
                  "x  x",
                  " xx "]));
    glyphs.insert('1', make_glyph([
                  "   " ,
                  " x ",
                  "xx ",
                  " x ",
                  " x ",
                  " x ",
                  "xxx"]));
    glyphs.insert('2', make_glyph([
                  "    " ,
                  "xxx ",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('3', make_glyph([
                  "    " ,
                  "xxx ",
                  "   x",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('4', make_glyph([
                  "    " ,
                  "   x",
                  "  x ",
                  " x  ",
                  "x  x",
                  "xxxx",
                  "   x"]));
    glyphs.insert('5', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('6', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "xxx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('7', make_glyph([
                  "    " ,
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "x   "]));
    glyphs.insert('8', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  " xx ",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('9', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  " xxx",
                  "   x",
                  "   x",
                  " xx "]));
    glyphs.insert('A', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x"]));
    glyphs.insert('B', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('C', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "x   ",
                  "x   ",
                  "x   ",
                  " xxx"]));
    glyphs.insert('D', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "xxx "]));
    glyphs.insert('E', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "xxxx"]));
    glyphs.insert('F', make_glyph([
                  "    " ,
                  "xxxx",
                  "x   ",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('G', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  "x   ",
                  "x xx",
                  "x  x",
                  " xxx"]));
    glyphs.insert('H', make_glyph([
                  "    " ,
                  "x  x",
                  "x  x",
                  "xxxx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('I', make_glyph([
                  " " ,
                  "x",
                  "x",
                  "x",
                  "x",
                  "x",
                  "x"]));
    glyphs.insert('J', make_glyph([
                  "    " ,
                  "   x",
                  "   x",
                  "   x",
                  "   x",
                  "x  x",
                  " xx "]));
    glyphs.insert('K', make_glyph([
                  "    " ,
                  "x  x",
                  "x x ",
                  "xx  ",
                  "x x ",
                  "x  x",
                  "x  x"]));
    glyphs.insert('L', make_glyph([
                  "   " ,
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "x  ",
                  "xxx"]));
    glyphs.insert('M', make_glyph([
                  "     " ,
                  "x   x",
                  "xx xx",
                  "x x x",
                  "x   x",
                  "x   x",
                  "x   x"]));
    glyphs.insert('N', make_glyph([
                  "    " ,
                  "x  x",
                  "xx x",
                  "x xx",
                  "x  x",
                  "x  x",
                  "x  x"]));
    glyphs.insert('O', make_glyph([
                  "    " ,
                  " xx ",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('P', make_glyph([
                  "    " ,
                  "xxx ",
                  "x  x",
                  "xxx ",
                  "x   ",
                  "x   ",
                  "x   "]));
    glyphs.insert('Q', make_glyph([
                  "     " ,
                  " xx  ",
                  "x  x ",
                  "x  x ",
                  "x  x ",
                  "x xx ",
                  " xx x"]));
    glyphs.insert('R', make_glyph([
                  "     " ,
                  "xxx  ",
                  "x  x ",
                  "xxx  ",
                  "x  x ",
                  "x  x ",
                  "x  x "]));
    glyphs.insert('S', make_glyph([
                  "    " ,
                  " xxx",
                  "x   ",
                  " xx ",
                  "   x",
                  "   x",
                  "xxx "]));
    glyphs.insert('T', make_glyph([
                  "     " ,
                  "xxxxx",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('U', make_glyph([
                  "    " ,
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  "x  x",
                  " xx "]));
    glyphs.insert('V', make_glyph([
                  "     " ,
                  "x   x",
                  "x   x",
                  "x   x",
                  "x   x",
                  " x x ",
                  "  x  "]));
    glyphs.insert('W', make_glyph([
                  "     " ,
                  "x   x",
                  "x   x",
                  "x   x",
                  "x x x",
                  "x x x",
                  " x x "]));
    glyphs.insert('X', make_glyph([
                  "     " ,
                  "x   x",
                  " x x ",
                  "  x  ",
                  " x x ",
                  "x   x",
                  "x   x"]));
    glyphs.insert('Y', make_glyph([
                  "     " ,
                  "x   x",
                  " x x ",
                  "  x  ",
                  "  x  ",
                  "  x  ",
                  "  x  "]));
    glyphs.insert('Z', make_glyph([
                  "    " ,
                  "xxxx",
                  "   x",
                  "  x ",
                  " x  ",
                  "x   ",
                  "xxxx"]));
    glyphs
}
<|endoftext|>


<commit_before>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{ControllerButton, ControllerAxisArgs, Key};
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

const UPS: u16 = 120;
const BULLET_RATE: f64 = 0.01;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        match controller.button {
            10 => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {
        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }

        // TODO: Actually use stick position value to affect rotation amount
        //       Actually use trigger position value affect boost amount
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        graphics::text(color::ORANGE,
                       22,
                       &format!("Score: {}", self.score),
                       &mut self.resources.font,
                       c.trans(10.0, 20.0).transform,
                       g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += (-0.06 * UPS as f64) * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += (0.06 * UPS as f64) * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 400.0 } else { 200.0 };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > 0.05 {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * 500.0);
        }

        // Remove bullets outside the viewport
        {
            // Shorten the lifetime of size
            let size = &self.world.size;
            self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > 1.0 {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy: Enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * 100.0, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        {
            // We introduce a scope to shorten the lifetime of the borrows below
            // The references are to avoid using self in the closure
            // (the borrow checker doesn't like that)
            let bullets = &mut self.world.bullets;
            let enemies = &mut self.world.enemies;
            let particles = &mut self.world.particles;

            bullets.retain(|bullet| {
                // Remove the first enemy that collides with a bullet (if any)
                // Add an explosion on its place
                if let Some((index, position)) = enemies.iter().enumerate()
                    .find(|&(_, enemy)| enemy.collides_with(bullet))
                    .map(|(index, enemy)| (index, enemy.position()))
                    {
                        Game::make_explosion(particles, position, 10);
                        enemies.remove(index);
                        false
                    } else {
                    true
                }
            });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<commit_msg>Replace magic numbers by constants<commit_after>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{ControllerButton, ControllerAxisArgs, Key};
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

// Constants related to time
const BULLETS_PER_SECOND: f64 = 100.0;
const BULLET_RATE: f64 = 1.0 / BULLETS_PER_SECOND;

const ENEMY_SPAWNS_PER_SECOND: f64 = 1.0;
const ENEMY_SPAWN_RATE: f64 = 1.0 / ENEMY_SPAWNS_PER_SECOND;

const TRAIL_PARTICLES_PER_SECOND: f64 = 20.0;
const TRAIL_PARTICLE_RATE: f64 = 1.0 / TRAIL_PARTICLES_PER_SECOND;

// Constants related to movement
const ADVANCE_SPEED: f64 = 200.0;
const BULLET_SPEED: f64 = 500.0;
const ENEMY_SPEED: f64 = 100.0;
const ROTATE_SPEED: f64 = 7.2;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        match controller.button {
            10 => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {
        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        graphics::text(color::ORANGE,
                       22,
                       &format!("Score: {}", self.score),
                       &mut self.resources.font,
                       c.trans(10.0, 20.0).transform,
                       g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += -ROTATE_SPEED * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += ROTATE_SPEED * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 2.0 * ADVANCE_SPEED } else { ADVANCE_SPEED };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > TRAIL_PARTICLE_RATE {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * BULLET_SPEED);
        }

        // Remove bullets outside the viewport
        {
            // Shorten the lifetime of size
            let size = &self.world.size;
            self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > ENEMY_SPAWN_RATE {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * ENEMY_SPEED, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        // We introduce a scope to shorten the lifetime of the borrows below
        {
            let bullets = &mut self.world.bullets;
            let enemies = &mut self.world.enemies;
            let particles = &mut self.world.particles;

            bullets.retain(|bullet| {
                // Remove the first enemy that collides with a bullet (if any)
                // Add an explosion on its place
                if let Some((index, position)) = enemies.iter().enumerate()
                    .find(|&(_, enemy)| enemy.collides_with(bullet))
                    .map(|(index, enemy)| (index, enemy.position()))
                    {
                        Game::make_explosion(particles, position, 10);
                        enemies.remove(index);
                        false
                    } else {
                    true
                }
            });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<|endoftext|>


<commit_before>
use colored::*;
use card::*;
use std::io;

pub struct Game{
    deck:       Deck,
    tableau:    Vec<Stack>,
    target:     Vec<Stack>,
    stack:      Stack
}

impl Game{

    pub fn new() -> Game{
        let mut deck = Deck::new();
        deck.shuffle();

        let tableau = (0..7).map(|_| Stack::new()).collect();
        let target = (0..4).map(|_| Stack::new()).collect();

        Game{
            deck:       deck,
            tableau:    tableau,
            target:     target,
            stack:      Stack::new()
        }
    }

    pub fn start(&mut self){
        println!("\n\t--------------------");
        println!("\tWelcome to solitaire!");
        println!("\t--------------------\n");

        // deal cards
        let tableau_len = self.tableau.len();
        let mut stacks_to_deal = tableau_len;

        while stacks_to_deal > 0 {
            for n in 1..(stacks_to_deal + 1){
                println!("{}", n);
                let card = self.deck.take(1);
                self.tableau[tableau_len - n].add_to_top(card);
            }
            stacks_to_deal = stacks_to_deal - 1;
        }

        self.display_board();

        // let mut input = String::new();

    // match io::stdin().read_line(&mut input) {
    //     Ok(n) => {
    //         println!("{} bytes read", n);
    //         println!("{}", input);
    //     }
    //     Err(error) => println!("error: {}", error),
    // }
    }

    fn display_board(&self){
        // deck
        let deck = "[🂠]".blue();

        // stack
        let stack = if self.stack.count() > 0 {
            "1, 2, 3"
        } else {
            ""
        };

        // targets
        let target = &self.target.iter().map(|stack|
            if stack.count() > 0 {
                stack.top_card().to_string()
            } else {
                String::from("🂠")
            }
        ).collect::<Vec<String>>();

        println!("[h]\t[s]\t\t[a]\t[b]\t[c]\t[d]");

        println!("{}\t{}\t\t[{}]\t[{}]\t[{}]\t[{}]", deck, stack, target[0], target[1], target[2], target[3]);

        let stacks = &self.tableau.iter().map(|stack|
            if stack.count() > 0 {
                stack.count().to_string().blue()
            } else {
                "🂠".normal()
            }
        ).collect::<Vec<ColoredString>>();

        // stacks
      println!("\n\t[1]\t[2]\t[3]\t[4]\t[5]\t[6]\t[7]");
        println!("\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]", stacks[0], stacks[1], stacks[2], stacks[3],
            stacks[4], stacks[5], stacks[6]);
    }
}<commit_msg>couple of visual updates<commit_after>
use colored::*;
use card::*;
use std::io;

pub struct Game{
    deck:       Deck,
    tableau:    Vec<Stack>,
    target:     Vec<Stack>,
    stack:      Stack
}

impl Game{

    pub fn new() -> Game{
        let mut deck = Deck::new();
        deck.shuffle();

        let tableau = (0..7).map(|_| Stack::new()).collect();
        let target = (0..4).map(|_| Stack::new()).collect();

        Game{
            deck:       deck,
            tableau:    tableau,
            target:     target,
            stack:      Stack::new()
        }
    }

    pub fn start(&mut self){
        println!("\n\t\t--------------------");
        println!("{}", "\t\tWelcome to Solitaire!".bold());
        println!("\t\t--------------------\n");

        // deal cards
        let tableau_len = self.tableau.len();
        let mut stacks_to_deal = tableau_len;

        while stacks_to_deal > 0 {
            for n in 1..(stacks_to_deal + 1){
                let card = self.deck.take(1);
                self.tableau[tableau_len - n].add_to_top(card);
            }
            stacks_to_deal = stacks_to_deal - 1;
        }

        self.display_board();

        // let mut input = String::new();

    // match io::stdin().read_line(&mut input) {
    //     Ok(n) => {
    //         println!("{} bytes read", n);
    //         println!("{}", input);
    //     }
    //     Err(error) => println!("error: {}", error),
    // }
    }

    fn display_board(&self){
        // deck
        let deck = "?".blue();

        // stack
        let stack = if self.stack.count() > 0 {
            "1, 2, 3"
        } else {
            ""
        };

        // targets
        let target = &self.target.iter().map(|stack|
            if stack.count() > 0 {
                stack.top_card().to_string()
            } else {
                String::from(" ")
            }
        ).collect::<Vec<String>>();

        println!("<h>\t<s>\t\t\t<a>\t<b>\t<c>\t<d>");

        println!("[{}]\t{}\t\t\t[{}]\t[{}]\t[{}]\t[{}]", deck, stack, target[0], target[1], target[2], target[3]);

        let stacks = &self.tableau.iter().map(|stack|
            stack.count().to_string().blue()
        ).collect::<Vec<ColoredString>>();

        // stacks
      println!("\n\t<1>\t<2>\t<3>\t<4>\t<5>\t<6>\t<7>");
        println!("\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]\t[{}]", stacks[0], stacks[1], stacks[2], stacks[3],
            stacks[4], stacks[5], stacks[6]);
    }
}<|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

pub struct Game {
    intended_word: String,
    guessed: Vec<GuessedRes>,
}

impl Game {
    pub fn new(intended_word: String) -> Game {
        let guessed = intended_word.chars().map(|ch| GuessedRes::new(ch, false)).collect();
        Game {
            intended_word: intended_word,
            guessed : guessed,
        }
    }

    pub fn intended_word<'r>(&'r self) -> &'r str {
        &self.intended_word[]
    }

    pub fn current_progress(&self) -> CurrentProgress {
        CurrentProgress { vec : self.guessed.iter().map(|x| x.to_enum()).collect() }
    }

    pub fn letters_left(&self) -> usize {
        self.guessed.iter().filter(|&x| !x.is_guessed).count()
    }

    pub fn guess(&mut self, guess : &str) {
        for ch in guess.chars() {
            self.guess_char(ch);
        }
    }

    fn guess_char(&mut self, ch : char) {
        for g_res in self.guessed.iter_mut().filter(|x| !x.is_guessed && x.ch==ch) {
            g_res.is_guessed = true;
        }
    }
}

struct GuessedRes {
    ch : char,
    is_guessed : bool,
}

impl GuessedRes {

    fn new(ch : char, is_guessed : bool) -> GuessedRes {
        GuessedRes {
            ch : ch,
            is_guessed : is_guessed,
        }
    }

    fn to_enum(&self) -> Guessed {
        if self.is_guessed {
            Guessed::Yes(self.ch)
        } else {
            Guessed::No
        }
    }
}

#[derive(Debug)]
pub enum Guessed {
    Yes(char),
    No,
}

#[derive(Debug)]
pub struct CurrentProgress {
    vec : Vec<Guessed>,
}

impl Display for CurrentProgress {
    fn fmt(&self, f : &mut Formatter) -> Result<(), Error> {
        let mut result = String::with_capacity(self.vec.len() * 2);
        for guess in self.vec.iter() {
            match *guess {
                Guessed::Yes(ch) => result.push(ch),
                Guessed::No => result.push('_'),
            }
            result.push(' ');
        }
        write!(f, "{}", result.as_slice())
    }
}
<commit_msg>pub type Guessed = Option<char><commit_after>use std::fmt::{Display, Error, Formatter};

pub struct Game {
    intended_word: String,
    guessed: Vec<GuessedRes>,
}

impl Game {
    pub fn new(intended_word: String) -> Game {
        let guessed = intended_word.chars().map(|ch| GuessedRes::new(ch, false)).collect();
        Game {
            intended_word: intended_word,
            guessed : guessed,
        }
    }

    pub fn intended_word<'r>(&'r self) -> &'r str {
        &self.intended_word[]
    }

    pub fn current_progress(&self) -> CurrentProgress {
        CurrentProgress { vec : self.guessed.iter().map(|x| x.to_enum()).collect() }
    }

    pub fn letters_left(&self) -> usize {
        self.guessed.iter().filter(|&x| !x.is_guessed).count()
    }

    pub fn guess(&mut self, guess : &str) {
        for ch in guess.chars() {
            self.guess_char(ch);
        }
    }

    fn guess_char(&mut self, ch : char) {
        for g_res in self.guessed.iter_mut().filter(|x| !x.is_guessed && x.ch==ch) {
            g_res.is_guessed = true;
        }
    }
}

struct GuessedRes {
    ch : char,
    is_guessed : bool,
}

impl GuessedRes {

    fn new(ch : char, is_guessed : bool) -> GuessedRes {
        GuessedRes {
            ch : ch,
            is_guessed : is_guessed,
        }
    }

    fn to_enum(&self) -> Guessed {
        if self.is_guessed {
            Some(self.ch)
        } else {
            None
        }
    }
}

pub type Guessed = Option<char>;

#[derive(Debug)]
pub struct CurrentProgress {
    vec : Vec<Guessed>,
}

impl CurrentProgress {
    #[allow(dead_code)]
    pub fn get_guessed_slice(&self) -> &[Guessed] {
        &self.vec[]
    }
}

impl Display for CurrentProgress {
    fn fmt(&self, f : &mut Formatter) -> Result<(), Error> {
        let mut result = String::with_capacity(self.vec.len() * 2);
        for guess in self.vec.iter() {
            match *guess {
                Some(ch) => result.push(ch),
                None => result.push('_'),
            }
            result.push(' ');
        }
        write!(f, "{}", result.as_slice())
    }
}
<|endoftext|>