<commit_before>extern crate libc;

use dim4::Dim4;
use defines::AfError;
use defines::Aftype;
use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong};

type MutAfArray = *mut self::libc::c_longlong;
type MutDouble  = *mut self::libc::c_double;
type MutUint    = *mut self::libc::c_uint;
type AfArray    = self::libc::c_longlong;
type DimT       = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_array(out: MutAfArray, data: *const c_void,
                       ndims: c_uint, dims: *const DimT, aftype: uint8_t) -> c_int;

    fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_get_type(out: *mut uint8_t, arr: AfArray) -> c_int;

    fn af_get_dims(dim0: *mut c_longlong, dim1: *mut c_longlong, dim2: *mut c_longlong,
                   dim3: *mut c_longlong, arr: AfArray) -> c_int;

    fn af_get_numdims(result: *mut c_uint, arr: AfArray) -> c_int;

    fn af_is_empty(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_scalar(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_row(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_column(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_vector(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_complex(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_real(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_double(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_single(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_realfloating(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_floating(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_integer(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_bool(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_get_data_ptr(data: *mut c_void, arr: AfArray) -> c_int;

    fn af_eval(arr: AfArray) -> c_int;

    fn af_retain_array(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_release_array(arr: AfArray) -> c_int;

    fn af_print_array(arr: AfArray) -> c_int;
}

pub struct Array {
    handle: i64,
}

macro_rules! is_func {
    ($fn_name: ident, $ffi_fn: ident) => (
        pub fn $fn_name(&self) -> Result<bool, AfError> {
            unsafe {
                let mut ret_val: i32 = 0;
                let err_val = $ffi_fn(&mut ret_val as *mut c_int, self.handle as AfArray);
                match err_val {
                    0 => Ok(ret_val>0),
                    _ => Err(AfError::from(err_val)),
                }
            }
        }
    )
}

impl Array {
    #[allow(unused_mut)]
    pub fn new<T>(dims: Dim4, slice: &[T], aftype: Aftype) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_create_array(&mut temp as MutAfArray,
                                          slice.as_ptr() as *const c_void,
                                          dims.ndims() as c_uint,
                                          dims.get().as_ptr() as * const c_longlong,
                                          aftype as uint8_t);
            match err_val {
                0 => Ok(Array {handle: temp}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn elements(&self) -> Result<i64, AfError> {
        unsafe {
            let mut ret_val: i64 = 0;
            let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray);
            match err_val {
                0 => Ok(ret_val),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get_type(&self) -> Result<Aftype, AfError> {
        unsafe {
            let mut ret_val: u8 = 0;
            let err_val = af_get_type(&mut ret_val as *mut uint8_t, self.handle as AfArray);
            match err_val {
                0 => Ok(Aftype::from(ret_val)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn dims(&self) -> Result<Dim4, AfError> {
        unsafe {
            let mut ret0: i64 = 0;
            let mut ret1: i64 = 0;
            let mut ret2: i64 = 0;
            let mut ret3: i64 = 0;
            let err_val = af_get_dims(&mut ret0 as *mut c_longlong, &mut ret1 as *mut c_longlong,
                                      &mut ret2 as *mut c_longlong, &mut ret3 as *mut c_longlong,
                                      self.handle as AfArray);
            match err_val {
                0 => Ok(Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn numdims(&self) -> Result<u32, AfError> {
        unsafe {
            let mut ret_val: u32 = 0;
            let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle as AfArray);
            match err_val {
                0 => Ok(ret_val),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64 {
        self.handle
    }

    pub fn host(&self, data:&mut [f64]) -> Result<(), AfError> {
        unsafe {
            let ret_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray);
            match ret_val {
                0 => Ok(()),
                _ => Err(AfError::from(ret_val)),
            }
        }
    }

    pub fn eval(&self) -> Result<(), AfError> {
        unsafe {
            let ret_val = af_eval(self.handle as AfArray);
            match ret_val {
                0 => Ok(()),
                _ => Err(AfError::from(ret_val)),
            }
        }
    }

    pub fn copy(&self) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    is_func!(is_empty, af_is_empty);
    is_func!(is_scalar, af_is_scalar);
    is_func!(is_row, af_is_row);
    is_func!(is_column, af_is_column);
    is_func!(is_vector, af_is_vector);
    is_func!(is_complex, af_is_complex);
    is_func!(is_double, af_is_double);
    is_func!(is_single, af_is_single);
    is_func!(is_real, af_is_real);
    is_func!(is_floating, af_is_floating);
    is_func!(is_integer, af_is_integer);
    is_func!(is_bool, af_is_bool);
}

impl From<i64> for Array {
    fn from(t: i64) -> Array {
        Array {handle: t}
    }
}

impl Clone for Array {
    fn clone(&self) -> Array {
        unsafe {
            let mut temp: i64 = 0;
            let ret_val = af_retain_array(&mut temp as MutAfArray, self.handle as AfArray);
            match ret_val {
                0 => Array {handle: temp},
                _ => panic!("Weak copy of Array failed with error code: {}", ret_val),
            }
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_array(self.handle);
            match ret_val {
                0 => (),
                _ => panic!("Weak copy of Array failed with error code: {}", ret_val),
            }
        }
    }
}

pub fn print(input: &Array) -> Result<(), AfError> {
    unsafe {
        let ret_val = af_print_array(input.get() as AfArray);
        match ret_val {
            0 => Ok(()),
            _ => Err(AfError::from(ret_val)),
        }
    }
}
<commit_msg>resolve type to be a generic type for the host function<commit_after>extern crate libc;

use dim4::Dim4;
use defines::AfError;
use defines::Aftype;
use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong};

type MutAfArray = *mut self::libc::c_longlong;
type MutDouble  = *mut self::libc::c_double;
type MutUint    = *mut self::libc::c_uint;
type AfArray    = self::libc::c_longlong;
type DimT       = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_array(out: MutAfArray, data: *const c_void,
                       ndims: c_uint, dims: *const DimT, aftype: uint8_t) -> c_int;

    fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_get_type(out: *mut uint8_t, arr: AfArray) -> c_int;

    fn af_get_dims(dim0: *mut c_longlong, dim1: *mut c_longlong, dim2: *mut c_longlong,
                   dim3: *mut c_longlong, arr: AfArray) -> c_int;

    fn af_get_numdims(result: *mut c_uint, arr: AfArray) -> c_int;

    fn af_is_empty(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_scalar(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_row(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_column(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_vector(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_complex(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_real(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_double(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_single(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_realfloating(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_floating(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_integer(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_is_bool(result: *mut c_int, arr: AfArray) -> c_int;

    fn af_get_data_ptr(data: *mut c_void, arr: AfArray) -> c_int;

    fn af_eval(arr: AfArray) -> c_int;

    fn af_retain_array(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int;

    fn af_release_array(arr: AfArray) -> c_int;

    fn af_print_array(arr: AfArray) -> c_int;
}

pub struct Array {
    handle: i64,
}

macro_rules! is_func {
    ($fn_name: ident, $ffi_fn: ident) => (
        pub fn $fn_name(&self) -> Result<bool, AfError> {
            unsafe {
                let mut ret_val: i32 = 0;
                let err_val = $ffi_fn(&mut ret_val as *mut c_int, self.handle as AfArray);
                match err_val {
                    0 => Ok(ret_val>0),
                    _ => Err(AfError::from(err_val)),
                }
            }
        }
    )
}

impl Array {
    #[allow(unused_mut)]
    pub fn new<T>(dims: Dim4, slice: &[T], aftype: Aftype) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_create_array(&mut temp as MutAfArray,
                                          slice.as_ptr() as *const c_void,
                                          dims.ndims() as c_uint,
                                          dims.get().as_ptr() as * const c_longlong,
                                          aftype as uint8_t);
            match err_val {
                0 => Ok(Array {handle: temp}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn elements(&self) -> Result<i64, AfError> {
        unsafe {
            let mut ret_val: i64 = 0;
            let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray);
            match err_val {
                0 => Ok(ret_val),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get_type(&self) -> Result<Aftype, AfError> {
        unsafe {
            let mut ret_val: u8 = 0;
            let err_val = af_get_type(&mut ret_val as *mut uint8_t, self.handle as AfArray);
            match err_val {
                0 => Ok(Aftype::from(ret_val)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn dims(&self) -> Result<Dim4, AfError> {
        unsafe {
            let mut ret0: i64 = 0;
            let mut ret1: i64 = 0;
            let mut ret2: i64 = 0;
            let mut ret3: i64 = 0;
            let err_val = af_get_dims(&mut ret0 as *mut c_longlong, &mut ret1 as *mut c_longlong,
                                      &mut ret2 as *mut c_longlong, &mut ret3 as *mut c_longlong,
                                      self.handle as AfArray);
            match err_val {
                0 => Ok(Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn numdims(&self) -> Result<u32, AfError> {
        unsafe {
            let mut ret_val: u32 = 0;
            let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle as AfArray);
            match err_val {
                0 => Ok(ret_val),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64 {
        self.handle
    }

    pub fn host<T>(&self, data: &mut [T]) -> Result<(), AfError> {
        unsafe {
            let ret_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray);
            match ret_val {
                0 => Ok(()),
                _ => Err(AfError::from(ret_val)),
            }
        }
    }

    pub fn eval(&self) -> Result<(), AfError> {
        unsafe {
            let ret_val = af_eval(self.handle as AfArray);
            match ret_val {
                0 => Ok(()),
                _ => Err(AfError::from(ret_val)),
            }
        }
    }

    pub fn copy(&self) -> Result<Array, AfError> {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray);
            match err_val {
                0 => Ok(Array::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    is_func!(is_empty, af_is_empty);
    is_func!(is_scalar, af_is_scalar);
    is_func!(is_row, af_is_row);
    is_func!(is_column, af_is_column);
    is_func!(is_vector, af_is_vector);
    is_func!(is_complex, af_is_complex);
    is_func!(is_double, af_is_double);
    is_func!(is_single, af_is_single);
    is_func!(is_real, af_is_real);
    is_func!(is_floating, af_is_floating);
    is_func!(is_integer, af_is_integer);
    is_func!(is_bool, af_is_bool);
}

impl From<i64> for Array {
    fn from(t: i64) -> Array {
        Array {handle: t}
    }
}

impl Clone for Array {
    fn clone(&self) -> Array {
        unsafe {
            let mut temp: i64 = 0;
            let ret_val = af_retain_array(&mut temp as MutAfArray, self.handle as AfArray);
            match ret_val {
                0 => Array {handle: temp},
                _ => panic!("Weak copy of Array failed with error code: {}", ret_val),
            }
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_array(self.handle);
            match ret_val {
                0 => (),
                _ => panic!("Weak copy of Array failed with error code: {}", ret_val),
            }
        }
    }
}

pub fn print(input: &Array) -> Result<(), AfError> {
    unsafe {
        let ret_val = af_print_array(input.get() as AfArray);
        match ret_val {
            0 => Ok(()),
            _ => Err(AfError::from(ret_val)),
        }
    }
}
<|endoftext|>


<commit_before>/*
src/audio.rs, 2017-08-20

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

//! Play sound effects and music.

use sdl2::mixer::{Channel, Chunk, Music};
use sdl2::mixer;

pub const MAX_VOLUME: i32 = mixer::MAX_VOLUME;
pub const DEFAULT_VOLUME: i32 = mixer::MAX_VOLUME;

/// Play sound effects.
pub trait SoundEffectPlayer {
    /// Play laser sound at next update.
    fn laser(&mut self);
    /// Play laser bomb launch sound at next update.
    fn laser_bomb_launch(&mut self);
    /// Play laser bomb explosion sound at next update.
    fn laser_bomb_explosion(&mut self);
    /// Play explosion sound at next update.
    fn explosion(&mut self);
    /// Play player laser hits laser cannon sound at next update.
    fn player_laser_hits_laser_cannon(&mut self);
    /// Play sound effects that are set to be played if
    /// sound effects are available.
    fn update(&mut self);
}

/// Sound effect's audio data and current `sdl2::mixer::Channel`
struct SoundEffect {
    channel: Channel,
    chunk: Chunk,
}

impl SoundEffect {
    /// Load new sound effect.
    fn new(file_path: &str) -> Result<SoundEffect, String> {
        let sound_effect = SoundEffect {
            channel: Channel::all(),
            chunk: Chunk::from_file(file_path)?,
        };

        Ok(sound_effect)
    }

    /// Play sound effect.
    ///
    /// Prints error message to standard output if there is sound effect
    /// playing error.
    fn play(&mut self) {
        self.channel = match self.channel.play(&self.chunk, 0) {
            Ok(channel) => channel,
            Err(message) => {
                println!("sound effect playing error: {}", message);
                Channel::all()
            },
        };
    }

    /// Change sound effect's volume.
    fn change_volume(&mut self, volume: Volume) {
        self.chunk.set_volume(volume.0);
    }
}

/// All sound effect's that the game requires.
struct AllSoundEffects {
    laser: SoundEffect,
    explosion: SoundEffect,
    laser_bomb_launch: SoundEffect,
    laser_bomb_explosion: SoundEffect,
    player_laser_hits_laser_cannon: SoundEffect,
}

impl AllSoundEffects {

    /// Loads all sound effects that the game requires.
    fn new(default_volume: Volume) -> Result<AllSoundEffects, String> {

        let mut sounds = AllSoundEffects {
            laser:                  SoundEffect::new("game_files/audio/laser.wav")?,
            explosion:              SoundEffect::new("game_files/audio/explosion.wav")?,
            laser_bomb_launch:      SoundEffect::new("game_files/audio/laser_bomb_launch.wav")?,
            laser_bomb_explosion:   SoundEffect::new("game_files/audio/laser_bomb_explosion.wav")?,
            player_laser_hits_laser_cannon:   SoundEffect::new("game_files/audio/player_laser_hits_laser_cannon.wav")?,
        };

        sounds.change_volume(default_volume);

        Ok(sounds)
    }

    /// All sound effects as array of mutable references.
    fn all_mut(&mut self) -> [&mut SoundEffect; 5] {
        [
            &mut self.laser,
            &mut self.explosion,
            &mut self.laser_bomb_launch,
            &mut self.laser_bomb_explosion,
            &mut self.player_laser_hits_laser_cannon,
        ]
    }

    /// Change volume of every sound effect.
    fn change_volume(&mut self, volume: Volume) {
        for effect in self.all_mut().iter_mut() {
            effect.change_volume(volume);
        }
    }
}

/// Wrapper for correct audio volume value.
#[derive(Copy, Clone)]
pub struct Volume(i32);

impl Volume {
    /// Create new volume value limited to [0; MAX_VOLUME].
    pub fn new(volume: i32) -> Volume {
        if volume > MAX_VOLUME {
            Volume(MAX_VOLUME)
        } else if volume < 0 {
            Volume(0)
        } else {
            Volume(volume)
        }
    }

    /// Get volume value.
    pub fn value(&self) -> i32 {
        self.0
    }
}

/// Stores sound effects and boolean values about
/// what sound effect should be played.
pub struct SoundEffectManager {
    sound_effects: Option<AllSoundEffects>,
    laser: bool,
    laser_bomb_launch: bool,
    laser_bomb_explosion: bool,
    explosion: bool,
    player_laser_hits_laser_cannon: bool,
}

impl SoundEffectManager {

    /// Create new `SoundEffectManager`.
    ///
    /// If argument `sound_effects` is `None`, sound effects are not played.
    fn new(sound_effects: Option<AllSoundEffects>) -> SoundEffectManager {
        SoundEffectManager {
            sound_effects,
            laser: false,
            laser_bomb_launch: false,
            laser_bomb_explosion: false,
            explosion: false,
            player_laser_hits_laser_cannon: false,
        }
    }

    /// Check if sound effect should be played and plays it with function `play`.
    ///
    /// Resets argument `play_sound_effect` to false if it was true.
    fn play(play_sound_effect: &mut bool, sound_effect: &mut SoundEffect ) {
        if *play_sound_effect {
            *play_sound_effect = false;
            sound_effect.play();
        }
    }

    /// Change volume of all sound effects if sound effects are available.
    fn change_volume(&mut self, volume: Volume) {
        if let Some(ref mut effects) = self.sound_effects {
            effects.change_volume(volume);
        }
    }
}

impl SoundEffectPlayer for SoundEffectManager {
    fn laser(&mut self) {
        self.laser = true;
    }

    fn laser_bomb_launch(&mut self) {
        self.laser_bomb_launch = true;
    }

    fn laser_bomb_explosion(&mut self) {
        self.laser_bomb_explosion = true;
    }

    fn explosion(&mut self) {
        self.explosion = true;
    }

    fn player_laser_hits_laser_cannon(&mut self) {
        self.player_laser_hits_laser_cannon = true;
    }

    fn update(&mut self) {
        if let Some(ref mut effects) = self.sound_effects {
            SoundEffectManager::play(&mut self.laser, &mut effects.laser);
            SoundEffectManager::play(&mut self.laser_bomb_launch, &mut effects.laser_bomb_launch);
            SoundEffectManager::play(&mut self.laser_bomb_explosion, &mut effects.laser_bomb_explosion);
            SoundEffectManager::play(&mut self.explosion, &mut effects.explosion);
            SoundEffectManager::play(&mut self.player_laser_hits_laser_cannon, &mut effects.player_laser_hits_laser_cannon);
        }
    }
}

/// Wrapper for `sdl2::mixer::Music`.
struct MusicWrapper {
    music: Music<'static>,
}

impl MusicWrapper {
    /// Load music from file.
    fn new(music_file_path: &str) -> Result<MusicWrapper, String> {
        let music_wrapper = MusicWrapper {
            music: Music::from_file(music_file_path)?,
        };

        Ok( music_wrapper )
    }

    /// Set music volume.
    fn set_volume(&mut self, volume: Volume) {
        Music::set_volume(volume.0);
    }

    /// Start playing music if it isn't already playing.
    ///
    /// If starting the music failed, an error message will
    /// be printed to the standard output.
    fn play(&mut self) {
        if !Music::is_playing() {
            if let Err(message) = self.music.play(-1) {
                println!("music error: {}", message);
            }
        }
    }
}

/// Store music, sound effects, volume values.
pub struct AudioManager {
    sound_effects: SoundEffectManager,
    music: Option<MusicWrapper>,
    music_volume: Volume,
    sound_effect_volume: Volume,
    audio_open: bool,
}

impl AudioManager {
    /// Create new `AudioManager`.
    ///
    /// Sound effects will be loaded from default locations. If there is
    /// sound effect loading error, all sound effects will be disabled.
    ///
    /// If there is a music loading error, music will be disabled.
    ///
    /// If there is a SDL_mixer init error, sound effects and music will be disabled.
    ///
    /// All errors will be printed to standard output.
    pub fn new(music_file_path: &str) -> AudioManager {
        println!("");

        let default_volume = Volume::new(DEFAULT_VOLUME);

        if let Err(error) = mixer::open_audio(44100, mixer::DEFAULT_FORMAT, mixer::DEFAULT_CHANNELS, 1024) {
            println!("SDL_mixer init error: {}", error);
            println!("Audio support disabled");

            AudioManager {
                sound_effects: SoundEffectManager::new(None),
                music: None,
                music_volume: default_volume,
                sound_effect_volume: default_volume,
                audio_open: false,
            }
        } else {
            println!("SDL_mixer version: {}", mixer::get_linked_version());

            let music = match MusicWrapper::new(music_file_path) {
                Ok(mut music) => {
                    music.set_volume(default_volume);
                    Some(music)
                }
                Err(error) => {
                    println!("music loading error: {}", error);
                    None
                }
            };

            let all_sound_effects = match AllSoundEffects::new(default_volume) {
                Ok(sound_effects) => Some(sound_effects),
                Err(error) => {
                    println!("error when loading sound effects: {}", error);
                    None
                },
            };

            AudioManager {
                sound_effects: SoundEffectManager::new(all_sound_effects),
                music,
                music_volume: default_volume,
                sound_effect_volume: default_volume,
                audio_open: true,
            }
        }
    }

    /// Get `SoundEffectManager`
    pub fn sound_effect_manager_mut(&mut self) -> &mut SoundEffectManager {
        &mut self.sound_effects
    }

    /// Set music volume.
    pub fn set_music_volume(&mut self, volume: Volume) {
        self.music_volume = volume;

        if let Some(ref mut music) = self.music {
            music.set_volume(volume);
        }
    }

    /// Start playing music.
    pub fn play_music(&mut self) {
        if let Some(ref mut music) = self.music {
            music.play();
        }
    }

    /// Set sound effect volume.
    pub fn set_sound_effect_volume(&mut self, volume: Volume) {
        self.sound_effect_volume = volume;

        self.sound_effects.change_volume(volume);
    }
}

impl Drop for AudioManager {
    /// Call function `sdl2::mixer::close_audio` if audio is opened.
    fn drop(&mut self) {
        if self.audio_open {
            mixer::close_audio();
        }
    }
}
<commit_msg>change default audio volume<commit_after>/*
src/audio.rs, 2017-09-02

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

//! Play sound effects and music.

use sdl2::mixer::{Channel, Chunk, Music};
use sdl2::mixer;

pub const MAX_VOLUME: i32 = mixer::MAX_VOLUME;
pub const DEFAULT_VOLUME: i32 = 88;

/// Play sound effects.
pub trait SoundEffectPlayer {
    /// Play laser sound at next update.
    fn laser(&mut self);
    /// Play laser bomb launch sound at next update.
    fn laser_bomb_launch(&mut self);
    /// Play laser bomb explosion sound at next update.
    fn laser_bomb_explosion(&mut self);
    /// Play explosion sound at next update.
    fn explosion(&mut self);
    /// Play player laser hits laser cannon sound at next update.
    fn player_laser_hits_laser_cannon(&mut self);
    /// Play sound effects that are set to be played if
    /// sound effects are available.
    fn update(&mut self);
}

/// Sound effect's audio data and current `sdl2::mixer::Channel`
struct SoundEffect {
    channel: Channel,
    chunk: Chunk,
}

impl SoundEffect {
    /// Load new sound effect.
    fn new(file_path: &str) -> Result<SoundEffect, String> {
        let sound_effect = SoundEffect {
            channel: Channel::all(),
            chunk: Chunk::from_file(file_path)?,
        };

        Ok(sound_effect)
    }

    /// Play sound effect.
    ///
    /// Prints error message to standard output if there is sound effect
    /// playing error.
    fn play(&mut self) {
        self.channel = match self.channel.play(&self.chunk, 0) {
            Ok(channel) => channel,
            Err(message) => {
                println!("sound effect playing error: {}", message);
                Channel::all()
            },
        };
    }

    /// Change sound effect's volume.
    fn change_volume(&mut self, volume: Volume) {
        self.chunk.set_volume(volume.0);
    }
}

/// All sound effect's that the game requires.
struct AllSoundEffects {
    laser: SoundEffect,
    explosion: SoundEffect,
    laser_bomb_launch: SoundEffect,
    laser_bomb_explosion: SoundEffect,
    player_laser_hits_laser_cannon: SoundEffect,
}

impl AllSoundEffects {

    /// Loads all sound effects that the game requires.
    fn new(default_volume: Volume) -> Result<AllSoundEffects, String> {

        let mut sounds = AllSoundEffects {
            laser:                  SoundEffect::new("game_files/audio/laser.wav")?,
            explosion:              SoundEffect::new("game_files/audio/explosion.wav")?,
            laser_bomb_launch:      SoundEffect::new("game_files/audio/laser_bomb_launch.wav")?,
            laser_bomb_explosion:   SoundEffect::new("game_files/audio/laser_bomb_explosion.wav")?,
            player_laser_hits_laser_cannon:   SoundEffect::new("game_files/audio/player_laser_hits_laser_cannon.wav")?,
        };

        sounds.change_volume(default_volume);

        Ok(sounds)
    }

    /// All sound effects as array of mutable references.
    fn all_mut(&mut self) -> [&mut SoundEffect; 5] {
        [
            &mut self.laser,
            &mut self.explosion,
            &mut self.laser_bomb_launch,
            &mut self.laser_bomb_explosion,
            &mut self.player_laser_hits_laser_cannon,
        ]
    }

    /// Change volume of every sound effect.
    fn change_volume(&mut self, volume: Volume) {
        for effect in self.all_mut().iter_mut() {
            effect.change_volume(volume);
        }
    }
}

/// Wrapper for correct audio volume value.
#[derive(Copy, Clone)]
pub struct Volume(i32);

impl Volume {
    /// Create new volume value limited to [0; MAX_VOLUME].
    pub fn new(volume: i32) -> Volume {
        if volume > MAX_VOLUME {
            Volume(MAX_VOLUME)
        } else if volume < 0 {
            Volume(0)
        } else {
            Volume(volume)
        }
    }

    /// Get volume value.
    pub fn value(&self) -> i32 {
        self.0
    }
}

/// Stores sound effects and boolean values about
/// what sound effect should be played.
pub struct SoundEffectManager {
    sound_effects: Option<AllSoundEffects>,
    laser: bool,
    laser_bomb_launch: bool,
    laser_bomb_explosion: bool,
    explosion: bool,
    player_laser_hits_laser_cannon: bool,
}

impl SoundEffectManager {

    /// Create new `SoundEffectManager`.
    ///
    /// If argument `sound_effects` is `None`, sound effects are not played.
    fn new(sound_effects: Option<AllSoundEffects>) -> SoundEffectManager {
        SoundEffectManager {
            sound_effects,
            laser: false,
            laser_bomb_launch: false,
            laser_bomb_explosion: false,
            explosion: false,
            player_laser_hits_laser_cannon: false,
        }
    }

    /// Check if sound effect should be played and plays it with function `play`.
    ///
    /// Resets argument `play_sound_effect` to false if it was true.
    fn play(play_sound_effect: &mut bool, sound_effect: &mut SoundEffect ) {
        if *play_sound_effect {
            *play_sound_effect = false;
            sound_effect.play();
        }
    }

    /// Change volume of all sound effects if sound effects are available.
    fn change_volume(&mut self, volume: Volume) {
        if let Some(ref mut effects) = self.sound_effects {
            effects.change_volume(volume);
        }
    }
}

impl SoundEffectPlayer for SoundEffectManager {
    fn laser(&mut self) {
        self.laser = true;
    }

    fn laser_bomb_launch(&mut self) {
        self.laser_bomb_launch = true;
    }

    fn laser_bomb_explosion(&mut self) {
        self.laser_bomb_explosion = true;
    }

    fn explosion(&mut self) {
        self.explosion = true;
    }

    fn player_laser_hits_laser_cannon(&mut self) {
        self.player_laser_hits_laser_cannon = true;
    }

    fn update(&mut self) {
        if let Some(ref mut effects) = self.sound_effects {
            SoundEffectManager::play(&mut self.laser, &mut effects.laser);
            SoundEffectManager::play(&mut self.laser_bomb_launch, &mut effects.laser_bomb_launch);
            SoundEffectManager::play(&mut self.laser_bomb_explosion, &mut effects.laser_bomb_explosion);
            SoundEffectManager::play(&mut self.explosion, &mut effects.explosion);
            SoundEffectManager::play(&mut self.player_laser_hits_laser_cannon, &mut effects.player_laser_hits_laser_cannon);
        }
    }
}

/// Wrapper for `sdl2::mixer::Music`.
struct MusicWrapper {
    music: Music<'static>,
}

impl MusicWrapper {
    /// Load music from file.
    fn new(music_file_path: &str) -> Result<MusicWrapper, String> {
        let music_wrapper = MusicWrapper {
            music: Music::from_file(music_file_path)?,
        };

        Ok( music_wrapper )
    }

    /// Set music volume.
    fn set_volume(&mut self, volume: Volume) {
        Music::set_volume(volume.0);
    }

    /// Start playing music if it isn't already playing.
    ///
    /// If starting the music failed, an error message will
    /// be printed to the standard output.
    fn play(&mut self) {
        if !Music::is_playing() {
            if let Err(message) = self.music.play(-1) {
                println!("music error: {}", message);
            }
        }
    }
}

/// Store music, sound effects, volume values.
pub struct AudioManager {
    sound_effects: SoundEffectManager,
    music: Option<MusicWrapper>,
    music_volume: Volume,
    sound_effect_volume: Volume,
    audio_open: bool,
}

impl AudioManager {
    /// Create new `AudioManager`.
    ///
    /// Sound effects will be loaded from default locations. If there is
    /// sound effect loading error, all sound effects will be disabled.
    ///
    /// If there is a music loading error, music will be disabled.
    ///
    /// If there is a SDL_mixer init error, sound effects and music will be disabled.
    ///
    /// All errors will be printed to standard output.
    pub fn new(music_file_path: &str) -> AudioManager {
        println!("");

        let default_volume = Volume::new(DEFAULT_VOLUME);

        if let Err(error) = mixer::open_audio(44100, mixer::DEFAULT_FORMAT, mixer::DEFAULT_CHANNELS, 1024) {
            println!("SDL_mixer init error: {}", error);
            println!("Audio support disabled");

            AudioManager {
                sound_effects: SoundEffectManager::new(None),
                music: None,
                music_volume: default_volume,
                sound_effect_volume: default_volume,
                audio_open: false,
            }
        } else {
            println!("SDL_mixer version: {}", mixer::get_linked_version());

            let music = match MusicWrapper::new(music_file_path) {
                Ok(mut music) => {
                    music.set_volume(default_volume);
                    Some(music)
                }
                Err(error) => {
                    println!("music loading error: {}", error);
                    None
                }
            };

            let all_sound_effects = match AllSoundEffects::new(default_volume) {
                Ok(sound_effects) => Some(sound_effects),
                Err(error) => {
                    println!("error when loading sound effects: {}", error);
                    None
                },
            };

            AudioManager {
                sound_effects: SoundEffectManager::new(all_sound_effects),
                music,
                music_volume: default_volume,
                sound_effect_volume: default_volume,
                audio_open: true,
            }
        }
    }

    /// Get `SoundEffectManager`
    pub fn sound_effect_manager_mut(&mut self) -> &mut SoundEffectManager {
        &mut self.sound_effects
    }

    /// Set music volume.
    pub fn set_music_volume(&mut self, volume: Volume) {
        self.music_volume = volume;

        if let Some(ref mut music) = self.music {
            music.set_volume(volume);
        }
    }

    /// Start playing music.
    pub fn play_music(&mut self) {
        if let Some(ref mut music) = self.music {
            music.play();
        }
    }

    /// Set sound effect volume.
    pub fn set_sound_effect_volume(&mut self, volume: Volume) {
        self.sound_effect_volume = volume;

        self.sound_effects.change_volume(volume);
    }
}

impl Drop for AudioManager {
    /// Call function `sdl2::mixer::close_audio` if audio is opened.
    fn drop(&mut self) {
        if self.audio_open {
            mixer::close_audio();
        }
    }
}
<|endoftext|>


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

// Metadata Structs
////////////////////////////////////////////////////////////////////////

/// Metadata struct for `FORM` chunks. Used for identifying a form
/// without loading the full form into memory.
///
/// Forms are a type of a chunk which contain additional chunks. These
/// are called out separately to chunks due to the large number of form
/// types.
///
/// **NOTE**: The `len` includes the 4 bytes in `id`. The remaining
/// length of the chunk after the `id` is `len - 4`.
#[derive(Debug)]
pub struct FormData {
    /// the length of the form, not counting the 8 byte chunk header
    pub len: u32,
    /// the 4 byte ascii id. The length includes these bytes.
    pub id: [u8; 0x4],
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    /// The 4 byte ascii id of the chunk
    pub id: [u8; 0x4],
    /// The length of the form, not counting the 8 byte chunk header
    pub len: u32,
}

impl From<FormData> for ChunkData {
    fn from(form_data: FormData) -> ChunkData {
        ChunkData{len: form_data.len, id: *b"FORM"}
    }
}

// Chunk Structs
////////////////////////////////////////////////////////////////////////

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Identifier: `b"Pict"`.
    /// Indicates the resource is an image.
    Pict,

    /// Identifier: `b"Snd "`.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: `b"Data"`.
    /// Indicates the resource is some data.
    Data,

    /// Identifier: `b"Exec"`.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    /// The type of the resource
    pub usage: Usage,
    /// The index of the resource
    pub num: u32,
    /// The starting address of the resource
    pub start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    /// a map of index value of a resource to the index entry of the
    /// resource.
    pub entries: HashMap<usize, IndexEntry>,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: `b"RIdx"`.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the blorb.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: `b"IFmd"`.
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: `b"Fspc"`.
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: `b"GLUL"`.
    /// Contains Glulx executable.
    /// This is a executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: `b"PNG "`.
    /// Contains a PNG image.
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: `b"JPEG"`.
    /// Contains a JPEG image.
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}
<commit_msg>switched a to an an in glulx doc comment<commit_after>use std::collections::HashMap;

// Metadata Structs
////////////////////////////////////////////////////////////////////////

/// Metadata struct for `FORM` chunks. Used for identifying a form
/// without loading the full form into memory.
///
/// Forms are a type of a chunk which contain additional chunks. These
/// are called out separately to chunks due to the large number of form
/// types.
///
/// **NOTE**: The `len` includes the 4 bytes in `id`. The remaining
/// length of the chunk after the `id` is `len - 4`.
#[derive(Debug)]
pub struct FormData {
    /// the length of the form, not counting the 8 byte chunk header
    pub len: u32,
    /// the 4 byte ascii id. The length includes these bytes.
    pub id: [u8; 0x4],
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    /// The 4 byte ascii id of the chunk
    pub id: [u8; 0x4],
    /// The length of the form, not counting the 8 byte chunk header
    pub len: u32,
}

impl From<FormData> for ChunkData {
    fn from(form_data: FormData) -> ChunkData {
        ChunkData{len: form_data.len, id: *b"FORM"}
    }
}

// Chunk Structs
////////////////////////////////////////////////////////////////////////

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Identifier: `b"Pict"`.
    /// Indicates the resource is an image.
    Pict,

    /// Identifier: `b"Snd "`.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: `b"Data"`.
    /// Indicates the resource is some data.
    Data,

    /// Identifier: `b"Exec"`.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    /// The type of the resource
    pub usage: Usage,
    /// The index of the resource
    pub num: u32,
    /// The starting address of the resource
    pub start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    /// a map of index value of a resource to the index entry of the
    /// resource.
    pub entries: HashMap<usize, IndexEntry>,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: `b"RIdx"`.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the blorb.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: `b"IFmd"`.
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: `b"Fspc"`.
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: `b"GLUL"`.
    /// Contains Glulx executable.
    /// This is an executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: `b"PNG "`.
    /// Contains a PNG image.
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: `b"JPEG"`.
    /// Contains a JPEG image.
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}
<|endoftext|>


<commit_before>use std::os;
use std::io::fs;
use std::io::{File, IoError, IoErrorKind, Reader, Writer, USER_RWX};
use std::io::process::{ProcessOutput, ProcessExit};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::SipHasher;

const HEADER: &'static [u8] = b"OBCF\x00\x01";
const FOOTER: &'static [u8] = b"END\x00";
const DEFAULT_BUF_SIZE: usize = 1024 * 64;

struct FileHash {
	hash: String,
	size: u64,
	modified: u64,
}

#[derive(Clone)]
pub struct Cache {
	file_hash: Arc<Mutex<HashMap<Path, Arc<Mutex<Option<FileHash>>>>>>,
	cache_dir: Path
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = os::homedir().unwrap().join_many(&[".octobuild", "cache"]);
		Cache {
			file_hash: Arc::new(Mutex::new(HashMap::new())),
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<ProcessOutput, IoError>>(&self, params: &str, inputs: &Vec<Path>, outputs: &Vec<Path>, worker: F) -> Result<ProcessOutput, IoError> {
		let hash = try! (self.generate_hash(params, inputs));
		let path = self.cache_dir.join(hash.slice(0, 2)).join(hash.slice(2, 4)).join(hash.slice_from(4));
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}

	fn generate_hash(&self, params: &str, inputs: &Vec<Path>) -> Result<String, IoError> {
		use std::hash::Writer;

		let mut hash = SipHasher::new();
		// str
		hash.write(params.as_bytes());
		hash.write(&[0]);
		// inputs
		for input in inputs.iter() {
			let file_hash = try! (self.get_file_hash(input));
			hash.write(file_hash.as_bytes());
		}
		Ok(format!("{:016x}", hash.result()))
	}

	pub fn get_file_hash(&self, path: &Path) -> Result<String, IoError> {
		// Get/create lock for file entry.
		let hash_lock = match self.file_hash.lock() {
			Ok(mut map) => {
				match map.entry(path.clone()) {
					Entry::Occupied(entry) => entry.get().clone(),
					Entry::Vacant(entry) => entry.insert(Arc::new(Mutex::new(None))).clone()
				}
			}
			Err(e) => {
				return Err(IoError {
					kind: IoErrorKind::OtherIoError,
					desc: "Mutex error",
					detail: Some(e.to_string())
				})
			}
		};
		// Get file hash.
		match hash_lock.lock() {
			Ok(mut hash_entry) => {
				// Validate entry, if exists.
				match *hash_entry {
					Some(ref value) => {
						let stat = try! (fs::stat(path));
						if value.size == stat.size && value.modified == stat.modified {
							return Ok(value.hash.clone());
						}
					}
					None => {}
				}
				// Calculate hash value.
				let stat = try! (fs::stat(path));
				let hash = try! (generate_file_hash(path));
				*hash_entry = Some(FileHash {
					hash: hash.clone(),
					size: stat.size,
					modified: stat.modified,
				});
				Ok(hash)
			}
			Err(e) => Err(IoError {
				kind: IoErrorKind::OtherIoError,
				desc: "Mutex error",
				detail: Some(e.to_string())
			})
		}
	}
}

fn generate_file_hash(path: &Path) -> Result<String, IoError> {
	use std::hash::Writer;
	let mut hash = SipHasher::new();
	let mut file = try! (File::open(path));
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		match file.read(&mut buf) {
			Ok(size) => {
				hash.write(&buf.as_slice()[0..size]);
			}
			Err(ref e) if e.kind == IoErrorKind::EndOfFile => break,
			Err(e) => return Err(e)
		}
	}
	Ok(format!("{:016x}", hash.result()))
}

fn write_cache(path: &Path, paths: &Vec<Path>, output: &ProcessOutput) -> Result<(), IoError> {
	if !output.status.success() {
		return Ok(());
	}
	try! (fs::mkdir_recursive(&path.dir_path(), USER_RWX));
	let mut stream = try! (File::create(path));
	try! (stream.write(HEADER));
	try! (stream.write_le_uint(paths.len()));
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	for path in paths.iter() {
		let mut file = try! (File::open(path));
		loop {
			match file.read(&mut buf) {
				Ok(size) => {
					try! (stream.write_le_uint(size));
					try! (stream.write(&buf.as_slice()[0..size]));
				}
				Err(ref e) if e.kind == IoErrorKind::EndOfFile => break,
				Err(e) => return Err(e)
			}
		}
		try! (stream.write_le_uint(0));
	}
	try! (write_output(&mut stream, output));
	try! (stream.write(FOOTER));
	Ok(())
}

fn read_cache(path: &Path, paths: &Vec<Path>) -> Result<ProcessOutput, IoError> {
	let mut stream = try! (File::open(path));
	if try! (stream.read_exact(HEADER.len())) != HEADER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file header",
			detail: Some(path.display().to_string())
		})
	}
	if try! (stream.read_le_uint()) != paths.len() {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Unexpected count of packed cached files",
			detail: Some(path.display().to_string())
		})
	}
	for path in paths.iter() {
		let mut file = try! (File::create(path));
		loop {
			let size = try! (stream.read_le_uint());
			if size == 0 {break;}
			let block = try! (stream.read_exact(size));
			try! (file.write(block.as_slice()));
		}
	}
	let output = try! (read_output(&mut stream));
	if try! (stream.read_exact(FOOTER.len())) != FOOTER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file footer",
			detail: Some(path.display().to_string())
		})
	}
	Ok(output)
}

fn write_blob(stream: &mut Writer, blob: &[u8]) -> Result<(), IoError> {
	try! (stream.write_le_uint(blob.len()));
	try! (stream.write(blob));
	Ok(())
}

fn read_blob(stream: &mut Reader) -> Result<Vec<u8>, IoError> {
	let size = try! (stream.read_le_uint());
	stream.read_exact(size)
}

fn write_output(stream: &mut Writer, output: &ProcessOutput) -> Result<(), IoError> {
	try! (write_blob(stream, output.output.as_slice()));
	try! (write_blob(stream, output.error.as_slice()));
	Ok(())
}

fn read_output(stream: &mut Reader) -> Result<ProcessOutput, IoError> {
	let output = try! (read_blob(stream));
	let error  = try! (read_blob(stream));
	Ok(ProcessOutput {
		status: ProcessExit::ExitStatus(0),
		output: output,
		error: error,
	})
}
<commit_msg>Support override cache path by OCTOBUILD_CACHE environment variable.<commit_after>use std::os;
use std::io::fs;
use std::io::{File, IoError, IoErrorKind, Reader, Writer, USER_RWX};
use std::io::process::{ProcessOutput, ProcessExit};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::SipHasher;

const HEADER: &'static [u8] = b"OBCF\x00\x01";
const FOOTER: &'static [u8] = b"END\x00";
const DEFAULT_BUF_SIZE: usize = 1024 * 64;

struct FileHash {
	hash: String,
	size: u64,
	modified: u64,
}

#[derive(Clone)]
pub struct Cache {
	file_hash: Arc<Mutex<HashMap<Path, Arc<Mutex<Option<FileHash>>>>>>,
	cache_dir: Path
}

impl Cache {
	pub fn new() -> Self {
		let cache_dir = match os::getenv("OCTOBUILD_CACHE") {
			Some(value) => Path::new(value),
			None => os::homedir().unwrap().join_many(&[".octobuild", "cache"])
		};
		Cache {
			file_hash: Arc::new(Mutex::new(HashMap::new())),
			cache_dir: cache_dir
		}
	}

	pub fn run_cached<F: Fn()->Result<ProcessOutput, IoError>>(&self, params: &str, inputs: &Vec<Path>, outputs: &Vec<Path>, worker: F) -> Result<ProcessOutput, IoError> {
		let hash = try! (self.generate_hash(params, inputs));
		let path = self.cache_dir.join(hash.slice(0, 2)).join(hash.slice(2, 4)).join(hash.slice_from(4));
		// Try to read data from cache.
		match read_cache(&path, outputs) {
			Ok(output) => {return Ok(output)}
			Err(_) => {}
		}
		// Run task and save result to cache.
		let output = try !(worker());
		try !(write_cache(&path, outputs, &output));
		Ok(output)
	}

	fn generate_hash(&self, params: &str, inputs: &Vec<Path>) -> Result<String, IoError> {
		use std::hash::Writer;

		let mut hash = SipHasher::new();
		// str
		hash.write(params.as_bytes());
		hash.write(&[0]);
		// inputs
		for input in inputs.iter() {
			let file_hash = try! (self.get_file_hash(input));
			hash.write(file_hash.as_bytes());
		}
		Ok(format!("{:016x}", hash.result()))
	}

	pub fn get_file_hash(&self, path: &Path) -> Result<String, IoError> {
		// Get/create lock for file entry.
		let hash_lock = match self.file_hash.lock() {
			Ok(mut map) => {
				match map.entry(path.clone()) {
					Entry::Occupied(entry) => entry.get().clone(),
					Entry::Vacant(entry) => entry.insert(Arc::new(Mutex::new(None))).clone()
				}
			}
			Err(e) => {
				return Err(IoError {
					kind: IoErrorKind::OtherIoError,
					desc: "Mutex error",
					detail: Some(e.to_string())
				})
			}
		};
		// Get file hash.
		match hash_lock.lock() {
			Ok(mut hash_entry) => {
				// Validate entry, if exists.
				match *hash_entry {
					Some(ref value) => {
						let stat = try! (fs::stat(path));
						if value.size == stat.size && value.modified == stat.modified {
							return Ok(value.hash.clone());
						}
					}
					None => {}
				}
				// Calculate hash value.
				let stat = try! (fs::stat(path));
				let hash = try! (generate_file_hash(path));
				*hash_entry = Some(FileHash {
					hash: hash.clone(),
					size: stat.size,
					modified: stat.modified,
				});
				Ok(hash)
			}
			Err(e) => Err(IoError {
				kind: IoErrorKind::OtherIoError,
				desc: "Mutex error",
				detail: Some(e.to_string())
			})
		}
	}
}

fn generate_file_hash(path: &Path) -> Result<String, IoError> {
	use std::hash::Writer;
	let mut hash = SipHasher::new();
	let mut file = try! (File::open(path));
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		match file.read(&mut buf) {
			Ok(size) => {
				hash.write(&buf.as_slice()[0..size]);
			}
			Err(ref e) if e.kind == IoErrorKind::EndOfFile => break,
			Err(e) => return Err(e)
		}
	}
	Ok(format!("{:016x}", hash.result()))
}

fn write_cache(path: &Path, paths: &Vec<Path>, output: &ProcessOutput) -> Result<(), IoError> {
	if !output.status.success() {
		return Ok(());
	}
	try! (fs::mkdir_recursive(&path.dir_path(), USER_RWX));
	let mut stream = try! (File::create(path));
	try! (stream.write(HEADER));
	try! (stream.write_le_uint(paths.len()));
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	for path in paths.iter() {
		let mut file = try! (File::open(path));
		loop {
			match file.read(&mut buf) {
				Ok(size) => {
					try! (stream.write_le_uint(size));
					try! (stream.write(&buf.as_slice()[0..size]));
				}
				Err(ref e) if e.kind == IoErrorKind::EndOfFile => break,
				Err(e) => return Err(e)
			}
		}
		try! (stream.write_le_uint(0));
	}
	try! (write_output(&mut stream, output));
	try! (stream.write(FOOTER));
	Ok(())
}

fn read_cache(path: &Path, paths: &Vec<Path>) -> Result<ProcessOutput, IoError> {
	let mut stream = try! (File::open(path));
	if try! (stream.read_exact(HEADER.len())) != HEADER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file header",
			detail: Some(path.display().to_string())
		})
	}
	if try! (stream.read_le_uint()) != paths.len() {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Unexpected count of packed cached files",
			detail: Some(path.display().to_string())
		})
	}
	for path in paths.iter() {
		let mut file = try! (File::create(path));
		loop {
			let size = try! (stream.read_le_uint());
			if size == 0 {break;}
			let block = try! (stream.read_exact(size));
			try! (file.write(block.as_slice()));
		}
	}
	let output = try! (read_output(&mut stream));
	if try! (stream.read_exact(FOOTER.len())) != FOOTER {
		return Err(IoError {
			kind: IoErrorKind::InvalidInput,
			desc: "Invalid cache file footer",
			detail: Some(path.display().to_string())
		})
	}
	Ok(output)
}

fn write_blob(stream: &mut Writer, blob: &[u8]) -> Result<(), IoError> {
	try! (stream.write_le_uint(blob.len()));
	try! (stream.write(blob));
	Ok(())
}

fn read_blob(stream: &mut Reader) -> Result<Vec<u8>, IoError> {
	let size = try! (stream.read_le_uint());
	stream.read_exact(size)
}

fn write_output(stream: &mut Writer, output: &ProcessOutput) -> Result<(), IoError> {
	try! (write_blob(stream, output.output.as_slice()));
	try! (write_blob(stream, output.error.as_slice()));
	Ok(())
}

fn read_output(stream: &mut Reader) -> Result<ProcessOutput, IoError> {
	let output = try! (read_blob(stream));
	let error  = try! (read_blob(stream));
	Ok(ProcessOutput {
		status: ProcessExit::ExitStatus(0),
		output: output,
		error: error,
	})
}
<|endoftext|>


<commit_before>#![allow(missing_copy_implementations)]

use std::io::Writer;

pub struct Size{
	width :uint,
	height :uint
}

impl Size{
	pub fn new(w :uint, h :uint)->Size{
		Size{ width: w, height: h }
	}
}

pub struct Position{
	x :f32,
	y :f32
}

impl Position{
	pub fn new(x :uint, y:uint)->Position{
		Position{ x: x as f32, y: y as f32 }
	}

	pub fn distance(&self, point :Position)->f32{
		use std::num::Float;
		let square = |&: x :f32| x * x;
		let offset_x = self.x - point.x;
		let offset_y = self.y - point.y;
		Float::sqrt(square(offset_x) + square(offset_y))
	}
}

#[derive(Clone)]
pub struct Color(f32, f32, f32, f32);

impl Color{
	fn f32_to_u8(v :f32)->u8{
		use std::num::ToPrimitive;
		match ToPrimitive::to_u8(&(v * 256f32)){
			Some(x) =>x,
			None =>if v > 0.5f32{ 255 }else{ 0 }
		}
	}

	pub fn r(&self)->u8{ Color::f32_to_u8(self.0) }

	pub fn g(&self)->u8{ Color::f32_to_u8(self.1) }

	pub fn b(&self)->u8{ Color::f32_to_u8(self.2) }

	pub fn rgb(r :u8, g :u8, b :u8)->Color{
		Color::rgba(r, g, b, 255)
	}

	pub fn rgba(r :u8, g :u8, b :u8, a :u8)->Color{
		Color(r as f32 / 256f32, g as f32 / 256f32, b as f32 / 256f32, a as f32 / 256f32)
	}

	pub fn transparent()->Color{
		Color(1f32, 1f32, 1f32, 0f32)
	}

	pub fn over(&self, dst :&mut Color){
		let &Color(lhs_r, lhs_g, lhs_b, lhs_a) = self;
		let &Color(rhs_r, rhs_g, rhs_b, rhs_a) = dst;
		let r = lhs_r * lhs_a + rhs_r * rhs_a * (1f32 - lhs_a);
		let g = lhs_g * lhs_a + rhs_g * rhs_a * (1f32 - lhs_a);
		let b = lhs_b * lhs_a + rhs_b * rhs_a * (1f32 - lhs_a);
		let a = if lhs_a > rhs_a { lhs_a }else { rhs_a };
		*dst = Color(r, g, b, a)
	}
}

pub struct Projection{
	pub x :u32,
	pub y :u32
}

impl Projection{
	fn f64_to_u32(v :f64)->u32{
		use std::f64;
		use std::u32;
		use std::num::ToPrimitive;
		match ToPrimitive::to_u32(&v){
			Some(v) =>v,
			None =>if v > f64::MAX_VALUE / 2f64{
				u32::MAX
			}else{
				0
			}
		}
	}
	pub fn new(canvas_size :&Size, position :Position)->Projection{
		use std::u32;
		let relative_x = position.x as f64 / canvas_size.width as f64;
		let x = Projection::f64_to_u32(relative_x * u32::MAX as f64);
		let relative_y = position.y as f64 / canvas_size.height as f64;
		let y = Projection::f64_to_u32(relative_y * u32::MAX as f64);
		Projection{ x: x, y: y }
	}
}

pub trait Layer{
	fn draw(&self, Projection)->Color;
}

pub struct Canvas{
	background :Color,
	size :Size
}

impl Canvas{
	pub fn new(background :Color, s :Size)->Canvas{
		Canvas{ size: s, background: background }
	}

	pub fn render<T :Layer>(&self, layer :T, writer :&mut Writer){
		let mut canvas = Vec::new();
		for _ in range(0, self.size.width * self.size.height){
			canvas.push(self.background.clone())
		}
		for x in range(0, self.size.width){
			for y in range(0, self.size.height){
				let index = x + self.size.width * y;
				let projection = Projection::new(&self.size, Position::new(x, y));
				layer.draw(projection).over(&mut canvas[index])
			}
		}
		writer.write_line("P3");
		writer.write_line(&*format!("{} {}", self.size.width, self.size.height));
		writer.write_line("255");
		for i in canvas.iter(){
			writer.write_line(&*format!("{} {} {}", i.r(), i.g(), i.b()));
		}
	}
}<commit_msg>remove warnings<commit_after>#![allow(missing_copy_implementations)]

use std::io::Writer;

pub struct Size{
	width :uint,
	height :uint
}

impl Size{
	pub fn new(w :uint, h :uint)->Size{
		Size{ width: w, height: h }
	}
}

pub struct Position{
	x :f32,
	y :f32
}

impl Position{
	pub fn new(x :uint, y:uint)->Position{
		Position{ x: x as f32, y: y as f32 }
	}

	pub fn distance(&self, point :Position)->f32{
		use std::num::Float;
		let square = |&: x :f32| x * x;
		let offset_x = self.x - point.x;
		let offset_y = self.y - point.y;
		Float::sqrt(square(offset_x) + square(offset_y))
	}
}

#[derive(Clone)]
pub struct Color(f32, f32, f32, f32);

impl Color{
	fn f32_to_u8(v :f32)->u8{
		use std::num::ToPrimitive;
		match ToPrimitive::to_u8(&(v * 256f32)){
			Some(x) =>x,
			None =>if v > 0.5f32{ 255 }else{ 0 }
		}
	}

	pub fn r(&self)->u8{ Color::f32_to_u8(self.0) }

	pub fn g(&self)->u8{ Color::f32_to_u8(self.1) }

	pub fn b(&self)->u8{ Color::f32_to_u8(self.2) }

	pub fn rgb(r :u8, g :u8, b :u8)->Color{
		Color::rgba(r, g, b, 255)
	}

	pub fn rgba(r :u8, g :u8, b :u8, a :u8)->Color{
		Color(r as f32 / 256f32, g as f32 / 256f32, b as f32 / 256f32, a as f32 / 256f32)
	}

	pub fn transparent()->Color{
		Color(1f32, 1f32, 1f32, 0f32)
	}

	pub fn over(&self, dst :&mut Color){
		let &Color(lhs_r, lhs_g, lhs_b, lhs_a) = self;
		let &Color(rhs_r, rhs_g, rhs_b, rhs_a) = dst;
		let r = lhs_r * lhs_a + rhs_r * rhs_a * (1f32 - lhs_a);
		let g = lhs_g * lhs_a + rhs_g * rhs_a * (1f32 - lhs_a);
		let b = lhs_b * lhs_a + rhs_b * rhs_a * (1f32 - lhs_a);
		let a = if lhs_a > rhs_a { lhs_a }else { rhs_a };
		*dst = Color(r, g, b, a)
	}
}

pub struct Projection{
	pub x :u32,
	pub y :u32
}

impl Projection{
	fn f64_to_u32(v :f64)->u32{
		use std::f64;
		use std::u32;
		use std::num::ToPrimitive;
		match ToPrimitive::to_u32(&v){
			Some(v) =>v,
			None =>if v > f64::MAX_VALUE / 2f64{
				u32::MAX
			}else{
				0
			}
		}
	}
	pub fn new(canvas_size :&Size, position :Position)->Projection{
		use std::u32;
		let relative_x = position.x as f64 / canvas_size.width as f64;
		let x = Projection::f64_to_u32(relative_x * u32::MAX as f64);
		let relative_y = position.y as f64 / canvas_size.height as f64;
		let y = Projection::f64_to_u32(relative_y * u32::MAX as f64);
		Projection{ x: x, y: y }
	}
}

pub trait Layer{
	fn draw(&self, Projection)->Color;
}

pub struct Canvas{
	background :Color,
	size :Size
}

impl Canvas{
	pub fn new(background :Color, s :Size)->Canvas{
		Canvas{ size: s, background: background }
	}

	pub fn render<T :Layer>(&self, layer :T, writer :&mut Writer){
		let mut canvas = Vec::new();
		for _ in range(0, self.size.width * self.size.height){
			canvas.push(self.background.clone())
		}
		for x in range(0, self.size.width){
			for y in range(0, self.size.height){
				let index = x + self.size.width * y;
				let projection = Projection::new(&self.size, Position::new(x, y));
				layer.draw(projection).over(&mut canvas[index])
			}
		}
		writer.write_line("P3").unwrap();
		writer.write_line(&*format!("{} {}", self.size.width, self.size.height)).unwrap();
		writer.write_line("255").unwrap();
		for i in canvas.iter(){
			writer.write_line(&*format!("{} {} {}", i.r(), i.g(), i.b())).unwrap();
		}
	}
}<|endoftext|>


<commit_before>use std::fmt;
use std::ops::{Add, Sub, Mul};
use std::iter::{Iterator,IntoIterator};

#[derive(Debug, Copy, Clone)]
pub struct Color {
    r: u8,
    g: u8,
    b: u8
}

pub enum NextColor {
    Red, Green, Blue, Done
}

pub struct ColorIterator {
    color: [u8;3],
    next: NextColor
}

impl Iterator for ColorIterator {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        match self.next {
            NextColor::Red => {
                self.next = NextColor::Green;
                Some(self.color[0])
            }
            NextColor::Green => {
                self.next = NextColor::Blue;
                Some(self.color[1])
            }
            NextColor::Blue => {
                self.next = NextColor::Done;
                Some(self.color[2])
            }
            NextColor::Done => None
        }
    }
}

impl IntoIterator for Color {
    type Item = u8;
    type IntoIter = ColorIterator;
    fn into_iter(self) -> Self::IntoIter {
        ColorIterator { color:[self.r, self.g, self.b], next:NextColor::Red }
    }
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color { r: r, g: g, b: b }
    }

    pub fn new_f64(r: f64, g: f64, b: f64) -> Color {
        Color::new(Color::clamp((r * 255.0) as i16),
                   Color::clamp((g * 255.0) as i16),
                   Color::clamp((b * 255.0) as i16))
    }

    #[inline(always)]
    pub fn r(&self) -> u8 {
        self.r
    }

    #[inline(always)]
    pub fn r_f64(&self) -> f64 {
        self.r() as f64 / 255.0
    }

    #[inline(always)]
    pub fn g(&self) -> u8 {
        self.g
    }

    #[inline(always)]
    pub fn g_f64(&self) -> f64 {
        self.g() as f64 / 255.0
    }

    #[inline(always)]
    pub fn b(&self) -> u8 {
        self.b
    }

    #[inline(always)]
    pub fn b_f64(&self) -> f64 {
        self.b() as f64 / 255.0
    }

    #[inline(always)]
    pub fn as_u32(&self) -> u32 {
        0xFF000000
            & (self.r as u32)
            & (self.g as u32) << 8
            & (self.b as u32) << 16
    }

    fn clamp(value: i16) -> u8 {
        if value < 0 {
            return 0;
        }

        if value > (u8::max_value() as i16) {
            return u8::max_value();
        }

        value as u8
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(r: {}, g: {}, b: {})", self.r(), self.g(), self.b())
    }
}

// Math

impl Add for Color {
    type Output = Color;

    fn add(self, other: Color) -> Color {
        let r = Color::clamp((self.r() as i16) + (other.r() as i16));
        let g = Color::clamp((self.g() as i16) + (other.g() as i16));
        let b = Color::clamp((self.b() as i16) + (other.b() as i16));

        Color::new(r, g, b)
    }
}

impl Sub for Color {
    type Output = Color;

    fn sub(self, other: Color) -> Color {
        let r = Color::clamp((self.r() as i16) - (other.r() as i16));
        let g = Color::clamp((self.g() as i16) - (other.g() as i16));
        let b = Color::clamp((self.b() as i16) - (other.b() as i16));

        Color::new(r, g, b)
    }
}

impl Mul for Color {
    type Output = Color;

    fn mul(self, other: Color) -> Color {
        let r = self.r_f64() * other.r_f64();
        let g = self.g_f64() * other.g_f64();
        let b = self.b_f64() * other.b_f64();

        Color::new_f64(r, g, b)
    }
}

impl Mul<f64> for Color {
    type Output = Color;

    fn mul(self, other: f64) -> Color {
        let r = self.r_f64() * other;
        let g = self.g_f64() * other;
        let b = self.b_f64() * other;

        Color::new_f64(r, g, b)
    }
}

// Factor methods for common colors
macro_rules! define_color {
    ($name: ident, $r: expr, $g: expr, $b: expr) => (
        #[inline(always)]
        pub fn $name() -> Color {
            Color::new($r, $g, $b)
        }
    )
}

impl Color {
    define_color!(black, 0, 0, 0);
    define_color!(white, 0xFF, 0xFF, 0xFF);
    define_color!(red, 0xFF, 0, 0);
    define_color!(green, 0, 0xFF, 0);
    define_color!(blue, 0, 0, 0xFF);
}
<commit_msg>Make Color an internal iterator<commit_after>use std::fmt;
use std::ops::{Add, Sub, Mul};
use std::iter::{Iterator,IntoIterator};

#[derive(Debug, Copy, Clone)]
pub struct Color {
    r: u8,
    g: u8,
    b: u8,
    next: NextColor,
}

#[derive(Debug, Copy, Clone)]
pub enum NextColor {
    Red, Green, Blue, Done
}

impl Iterator for Color{
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        match self.next {
            NextColor::Red => {
                self.next = NextColor::Green;
                Some(self.r)
            }
            NextColor::Green => {
                self.next = NextColor::Blue;
                Some(self.g)
            }
            NextColor::Blue => {
                self.next = NextColor::Done;
                Some(self.b)
            }
            NextColor::Done => None
        }
    }
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color { r: r, g: g, b: b, next: NextColor::Red }
    }

    pub fn new_f64(r: f64, g: f64, b: f64) -> Color {
        Color::new(Color::clamp((r * 255.0) as i16),
                   Color::clamp((g * 255.0) as i16),
                   Color::clamp((b * 255.0) as i16))
    }

    #[inline(always)]
    pub fn r(&self) -> u8 {
        self.r
    }

    #[inline(always)]
    pub fn r_f64(&self) -> f64 {
        self.r() as f64 / 255.0
    }

    #[inline(always)]
    pub fn g(&self) -> u8 {
        self.g
    }

    #[inline(always)]
    pub fn g_f64(&self) -> f64 {
        self.g() as f64 / 255.0
    }

    #[inline(always)]
    pub fn b(&self) -> u8 {
        self.b
    }

    #[inline(always)]
    pub fn b_f64(&self) -> f64 {
        self.b() as f64 / 255.0
    }

    #[inline(always)]
    pub fn as_u32(&self) -> u32 {
        0xFF000000
            & (self.r as u32)
            & (self.g as u32) << 8
            & (self.b as u32) << 16
    }

    fn clamp(value: i16) -> u8 {
        if value < 0 {
            return 0;
        }

        if value > (u8::max_value() as i16) {
            return u8::max_value();
        }

        value as u8
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(r: {}, g: {}, b: {})", self.r(), self.g(), self.b())
    }
}

// Math

impl Add for Color {
    type Output = Color;

    fn add(self, other: Color) -> Color {
        let r = Color::clamp((self.r() as i16) + (other.r() as i16));
        let g = Color::clamp((self.g() as i16) + (other.g() as i16));
        let b = Color::clamp((self.b() as i16) + (other.b() as i16));

        Color::new(r, g, b)
    }
}

impl Sub for Color {
    type Output = Color;

    fn sub(self, other: Color) -> Color {
        let r = Color::clamp((self.r() as i16) - (other.r() as i16));
        let g = Color::clamp((self.g() as i16) - (other.g() as i16));
        let b = Color::clamp((self.b() as i16) - (other.b() as i16));

        Color::new(r, g, b)
    }
}

impl Mul for Color {
    type Output = Color;

    fn mul(self, other: Color) -> Color {
        let r = self.r_f64() * other.r_f64();
        let g = self.g_f64() * other.g_f64();
        let b = self.b_f64() * other.b_f64();

        Color::new_f64(r, g, b)
    }
}

impl Mul<f64> for Color {
    type Output = Color;

    fn mul(self, other: f64) -> Color {
        let r = self.r_f64() * other;
        let g = self.g_f64() * other;
        let b = self.b_f64() * other;

        Color::new_f64(r, g, b)
    }
}

// Factor methods for common colors
macro_rules! define_color {
    ($name: ident, $r: expr, $g: expr, $b: expr) => (
        #[inline(always)]
        pub fn $name() -> Color {
            Color::new($r, $g, $b)
        }
    )
}

impl Color {
    define_color!(black, 0, 0, 0);
    define_color!(white, 0xFF, 0xFF, 0xFF);
    define_color!(red, 0xFF, 0, 0);
    define_color!(green, 0, 0xFF, 0);
    define_color!(blue, 0, 0, 0xFF);
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::rc::Rc;
use digit_slice::{DigitSlice};

pub enum Shape<'a, N: 'a + Noun> {
    // A natural number represented as a little-endian sequence of 8-bit
    // digits.
    Atom(&'a [u8]),
    // An ordered pair of nouns.
    Cell(&'a N, &'a N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
pub trait Noun: Sized {
    fn get<'a>(&'a self) -> Shape<'a, Self>;
}

pub trait Context: Sized {
    type Noun: Noun;

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun;

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun;
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun<C: Context>(self, &mut C) -> C::Noun;
}

impl<T> ToNoun for T where T: DigitSlice {
    fn to_noun<C: Context>(self, ctx: &mut C) -> C::Noun {
        ctx.atom(self.as_digits())
    }
}

/// Trait for constructing nouns without a Builder instance for Builder types
/// that don't need a common instance for constructing nouns.
///
/// By convention if a Builder implements Default, it's assumed that Builder
/// state doesn't matter and new Builders can be constructed at will.
pub trait Build<T> : Context {
    fn noun(T) -> Self::Noun;
}

impl<C, T> Build<T> for C
    where T: ToNoun,
          C: Context + Default
{
    fn noun(val: T) -> C::Noun {
        let mut ctx: C = Default::default();
        val.to_noun(&mut ctx)
    }
}

#[derive(Clone, PartialEq, Eq)]
enum HeapNounInner {
    Atom(Vec<u8>),
    Cell(Rc<HeapNoun>, Rc<HeapNoun>),
}

#[derive(Clone, PartialEq, Eq)]
pub struct HeapNoun(HeapNounInner);

impl Noun for HeapNoun {
    fn get<'a>(&'a self) -> Shape<'a, Self> {
        match self.0 {
            HeapNounInner::Atom(ref v) => Shape::Atom(&v),
            HeapNounInner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }
}

#[derive(Default)]
pub struct Heap;

impl Context for Heap {
    type Noun = HeapNoun;

    /// Build a new atom noun.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun {
        HeapNoun(HeapNounInner::Atom(digits.to_vec()))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun {
        HeapNoun(HeapNounInner::Cell(Rc::new(a), Rc::new(b)))
    }
}

#[cfg(test)]
mod tests {
    use super::{Heap, Build};

    #[test]
    fn scratch() {
        let x = Heap::noun(123u32);
        assert!(x == Heap::noun(123u8));
    }
}
<commit_msg>New API work<commit_after>use std::rc::Rc;
use digit_slice::DigitSlice;

pub enum Shape<'a, N: 'a + Noun> {
    // A natural number represented as a little-endian sequence of 8-bit
    // digits.
    Atom(&'a [u8]),
    // An ordered pair of nouns.
    Cell(&'a N, &'a N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
pub trait Noun: Sized+Clone {
    fn get<'a>(&'a self) -> Shape<'a, Self>;

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize;

    /// Run a memoizing fold over the noun
    fn fold<'a, F, G, T: Clone>(&'a self, leaf: &mut F, branch: &mut G) -> T
        where F: FnMut(&[u8]) -> T,
              G: FnMut(&T, &T) -> T
    {
        /*
        use std::collections::HashMap;
        fn g<'a, F, T: Clone>(noun: &'a Self, memo: &mut HashMap<usize, T>, leaf: &mut F, branch: &mut G) -> T
            where F: FnMut(&[u8]) -> T,
                  G: FnMut(&T, &T) -> T
        {
            let key = noun.addr();
            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = h(noun, memo, f);
                memo.insert(key, ret.clone());
                ret
            }
        }

        fn h<'a, F, T: Clone>(noun: &'a Noun, memo: &mut HashMap<usize, T>, f: &mut F) -> T
            where F: FnMut(FoldState<'a, T>) -> T
        {
            match noun {
                &Atom(ref a) => f(FoldState::Atom(*a)),
                &BigAtom(ref a) => f(FoldState::BigAtom(a)),
                &Cell(ref p, ref q) => {
                    let p = g(p, memo, f);
                    let q = g(q, memo, f);
                    f(FoldState::Cell(p, q))
                }
            }
        }

        h(self, &mut HashMap::new(), &mut f)
        */
        match self.get() {
            Shape::Atom(x) => leaf(x),
            Shape::Cell(ref a, ref b) => {
                let a = a.fold(leaf, branch);
                let b = b.fold(leaf, branch);
                branch(&a, &b)
            }
        }
    }
}

pub trait Context: Sized {
    type Noun: Noun;

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun;

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun;

    fn noun<T: ToNoun>(&mut self, item: T) -> Self::Noun {
        item.to_noun(self)
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun<C: Context>(self, &mut C) -> C::Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun<C: Context>(self, ctx: &mut C) -> C::Noun {
        ctx.atom(self.as_digits())
    }
}

#[derive(Clone, PartialEq, Eq)]
enum HeapNounInner {
    Atom(Vec<u8>),
    Cell(Rc<HeapNoun>, Rc<HeapNoun>),
}

#[derive(Clone, PartialEq, Eq)]
pub struct HeapNoun(HeapNounInner);

impl Noun for HeapNoun {
    fn get<'a>(&'a self) -> Shape<'a, Self> {
        match self.0 {
            HeapNounInner::Atom(ref v) => Shape::Atom(&v),
            HeapNounInner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }
}

#[derive(Default)]
pub struct Heap;

impl Context for Heap {
    type Noun = HeapNoun;

    /// Build a new atom noun.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun {
        HeapNoun(HeapNounInner::Atom(digits.to_vec()))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun {
        HeapNoun(HeapNounInner::Cell(Rc::new(a), Rc::new(b)))
    }
}

#[cfg(test)]
mod tests {
    use super::{Context, Heap};

    #[test]
    fn scratch() {
        let x = Heap.noun(123u32);
        assert!(x == Heap.noun(123u8));
    }
}
<|endoftext|>


<commit_before>use crypto::random_zbase32;
use hyper::{StatusCode};
use std::error::Error;
use std::fmt;

/// Union of all possible runtime error types.
#[derive(Debug)]
pub enum BrokerError {
    /// User input error, which results in 400
    Input(String),
    /// Identity provider error, which results in 503
    Provider(String),
    /// Identity provider request error, which results in 400
    ProviderInput(String),
    /// Internal errors, which result in 500
    Internal(String),
    /// User was rate limited, results in 413
    RateLimited,
    /// User session not found, results in 400
    SessionExpired,
    /// Result status used by bridges to cancel a request
    ProviderCancelled,
}

impl BrokerError {
    /// Log this error at the appropriate log level.
    /// Internal errors return a reference number for the error.
    pub fn log(&self) -> Option<String> {
        match *self {
            // User errors only at debug level.
            ref err @ BrokerError::Input(_)
                | ref err @ BrokerError::ProviderInput(_)
                | ref err @ BrokerError::RateLimited
                | ref err @ BrokerError::SessionExpired
                | ref err @ BrokerError::ProviderCancelled
                => {
                debug!("{}", err.description());
                None
            },
            // Provider errors can be noteworthy, especially when
            // the issue is network related.
            ref err @ BrokerError::Provider(_) => {
                info!("{}", err.description());
                None
            },
            // Internal errors should ring alarm bells.
            ref err @ BrokerError::Internal(_) => {
                let reference = random_zbase32(6);
                error!("[REF:{}] {}", err.description(), reference);
                Some(reference)
            },
        }
    }

    /// Get the HTTP status code for this error.
    pub fn http_status_code(&self) -> StatusCode {
        match *self {
            BrokerError::Input(_)
                | BrokerError::ProviderInput(_)
                | BrokerError::SessionExpired
                => StatusCode::BadRequest,
            BrokerError::Provider(_) => StatusCode::ServiceUnavailable,
            BrokerError::Internal(_) => StatusCode::InternalServerError,
            BrokerError::RateLimited => StatusCode::TooManyRequests,
            // Internal status that should never bubble this far
            BrokerError::ProviderCancelled => unreachable!(),
        }
    }

    /// Get the OAuth2 error code for this error
    pub fn oauth_error_code(&self) -> &str {
        match *self {
            BrokerError::Input(_) => "invalid_request",
            BrokerError::Provider(_)
                | BrokerError::ProviderInput(_)
                => "temporarily_unavailable",
            BrokerError::Internal(_) => "server_error",
            // We will never redirect for these types of errors
            BrokerError::RateLimited
                | BrokerError::SessionExpired
                // Internal status that should never bubble this far
                | BrokerError::ProviderCancelled
                => unreachable!(),
        }
    }
}

impl Error for BrokerError {
    fn description(&self) -> &str {
        match *self {
            BrokerError::Input(ref description)
                | BrokerError::Provider(ref description)
                | BrokerError::ProviderInput(ref description)
                | BrokerError::Internal(ref description)
                => description,
            BrokerError::RateLimited => "too many requests",
            BrokerError::SessionExpired => "session has expired",
            BrokerError::ProviderCancelled => "bridge cancelled the request",
        }
    }
}

impl fmt::Display for BrokerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

/// Result type with `BrokerError` for errors.
pub type BrokerResult<T> = Result<T, BrokerError>;
<commit_msg>Fix format of logging with reference number<commit_after>use crypto::random_zbase32;
use hyper::{StatusCode};
use std::error::Error;
use std::fmt;

/// Union of all possible runtime error types.
#[derive(Debug)]
pub enum BrokerError {
    /// User input error, which results in 400
    Input(String),
    /// Identity provider error, which results in 503
    Provider(String),
    /// Identity provider request error, which results in 400
    ProviderInput(String),
    /// Internal errors, which result in 500
    Internal(String),
    /// User was rate limited, results in 413
    RateLimited,
    /// User session not found, results in 400
    SessionExpired,
    /// Result status used by bridges to cancel a request
    ProviderCancelled,
}

impl BrokerError {
    /// Log this error at the appropriate log level.
    /// Internal errors return a reference number for the error.
    pub fn log(&self) -> Option<String> {
        match *self {
            // User errors only at debug level.
            ref err @ BrokerError::Input(_)
                | ref err @ BrokerError::ProviderInput(_)
                | ref err @ BrokerError::RateLimited
                | ref err @ BrokerError::SessionExpired
                | ref err @ BrokerError::ProviderCancelled
                => {
                debug!("{}", err.description());
                None
            },
            // Provider errors can be noteworthy, especially when
            // the issue is network related.
            ref err @ BrokerError::Provider(_) => {
                info!("{}", err.description());
                None
            },
            // Internal errors should ring alarm bells.
            ref err @ BrokerError::Internal(_) => {
                let reference = random_zbase32(6);
                error!("[REF:{}] {}", reference, err.description());
                Some(reference)
            },
        }
    }

    /// Get the HTTP status code for this error.
    pub fn http_status_code(&self) -> StatusCode {
        match *self {
            BrokerError::Input(_)
                | BrokerError::ProviderInput(_)
                | BrokerError::SessionExpired
                => StatusCode::BadRequest,
            BrokerError::Provider(_) => StatusCode::ServiceUnavailable,
            BrokerError::Internal(_) => StatusCode::InternalServerError,
            BrokerError::RateLimited => StatusCode::TooManyRequests,
            // Internal status that should never bubble this far
            BrokerError::ProviderCancelled => unreachable!(),
        }
    }

    /// Get the OAuth2 error code for this error
    pub fn oauth_error_code(&self) -> &str {
        match *self {
            BrokerError::Input(_) => "invalid_request",
            BrokerError::Provider(_)
                | BrokerError::ProviderInput(_)
                => "temporarily_unavailable",
            BrokerError::Internal(_) => "server_error",
            // We will never redirect for these types of errors
            BrokerError::RateLimited
                | BrokerError::SessionExpired
                // Internal status that should never bubble this far
                | BrokerError::ProviderCancelled
                => unreachable!(),
        }
    }
}

impl Error for BrokerError {
    fn description(&self) -> &str {
        match *self {
            BrokerError::Input(ref description)
                | BrokerError::Provider(ref description)
                | BrokerError::ProviderInput(ref description)
                | BrokerError::Internal(ref description)
                => description,
            BrokerError::RateLimited => "too many requests",
            BrokerError::SessionExpired => "session has expired",
            BrokerError::ProviderCancelled => "bridge cancelled the request",
        }
    }
}

impl fmt::Display for BrokerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

/// Result type with `BrokerError` for errors.
pub type BrokerResult<T> = Result<T, BrokerError>;
<|endoftext|>


<commit_before>// Copyright 2015 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

pub enum Error {
    DimensionMismatch,
    IllegalParameter(usize),
    DiagonalElementZero(usize),
}
<commit_msg>Derive debug for error<commit_after>// Copyright 2015 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

#[derive(Debug)]
pub enum Error {
    DimensionMismatch,
    IllegalParameter(usize),
    DiagonalElementZero(usize),
}
<|endoftext|>