<commit_before>use std::collections::HashMap;
use std::convert::TryFrom;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};

use rustc::ty::layout::Size;

use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Debug)]
pub struct FileHandle {
    file: File,
}

pub struct FileHandler {
    handles: HashMap<i32, FileHandle>,
    low: i32,
}

impl Default for FileHandler {
    fn default() -> Self {
        FileHandler {
            handles: Default::default(),
            // 0, 1 and 2 are reserved for stdin, stdout and stderr.
            low: 3,
        }
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn open(
        &mut self,
        path_op: OpTy<'tcx, Tag>,
        flag_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("open")?;

        let flag = this.read_scalar(flag_op)?.to_i32()?;

        let mut options = OpenOptions::new();

        let o_rdonly = this.eval_libc_i32("O_RDONLY")?;
        let o_wronly = this.eval_libc_i32("O_WRONLY")?;
        let o_rdwr = this.eval_libc_i32("O_RDWR")?;
        // The first two bits of the flag correspond to the access mode in linux, macOS and
        // windows. We need to check that in fact the access mode flags for the current platform
        // only use these two bits, otherwise we are in an unsupported platform and should error.
        if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
            throw_unsup_format!("Access mode flags on this platform are unsupported");
        }
        // Now we check the access mode
        let access_mode = flag & 0b11;

        if access_mode == o_rdonly {
            options.read(true);
        } else if access_mode == o_wronly {
            options.write(true);
        } else if access_mode == o_rdwr {
            options.read(true).write(true);
        } else {
            throw_unsup_format!("Unsupported access mode {:#x}", access_mode);
        }
        // We need to check that there aren't unsupported options in `flag`. For this we try to
        // reproduce the content of `flag` in the `mirror` variable using only the supported
        // options.
        let mut mirror = access_mode;

        let o_append = this.eval_libc_i32("O_APPEND")?;
        if flag & o_append != 0 {
            options.append(true);
            mirror |= o_append;
        }
        let o_trunc = this.eval_libc_i32("O_TRUNC")?;
        if flag & o_trunc != 0 {
            options.truncate(true);
            mirror |= o_trunc;
        }
        let o_creat = this.eval_libc_i32("O_CREAT")?;
        if flag & o_creat != 0 {
            options.create(true);
            mirror |= o_creat;
        }
        let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?;
        if flag & o_cloexec != 0 {
            // We do not need to do anything for this flag because `std` already sets it.
            // (Technically we do not support *not* setting this flag, but we ignore that.)
            mirror |= o_cloexec;
        }
        // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
        // then we throw an error.
        if flag != mirror {
            throw_unsup_format!("unsupported flags {:#x}", flag & !mirror);
        }

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let fd = options.open(path).map(|file| {
            let mut fh = &mut this.machine.file_handler;
            fh.low += 1;
            fh.handles.insert(fh.low, FileHandle { file }).unwrap_none();
            fh.low
        });

        this.try_unwrap_io_result(fd)
    }

    fn fcntl(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        cmd_op: OpTy<'tcx, Tag>,
        _arg1_op: Option<OpTy<'tcx, Tag>>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("fcntl")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let cmd = this.read_scalar(cmd_op)?.to_i32()?;
        // We only support getting the flags for a descriptor.
        if cmd == this.eval_libc_i32("F_GETFD")? {
            // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
            // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
            // always sets this flag when opening a file. However we still need to check that the
            // file itself is open.
            if this.machine.file_handler.handles.contains_key(&fd) {
                Ok(this.eval_libc_i32("FD_CLOEXEC")?)
            } else {
                this.handle_not_found()
            }
        } else {
            throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
        }
    }

    fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("close")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;

        if let Some(handle) = this.machine.file_handler.handles.remove(&fd) {
            // `File::sync_all` does the checks that are done when closing a file. We do this to
            // to handle possible errors correctly.
            let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32));
            // Now we actually close the file.
            drop(handle);
            // And return the result.
            result
        } else {
            this.handle_not_found()
        }
    }

    fn read(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("read")?;

        let ptr_size = this.pointer_size().bits();

        let count = this
            .read_scalar(count_op)?
            .to_machine_usize(&*this.tcx)?
            .min(1 << (ptr_size - 1));
        // Reading zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            let count = isize::try_from(count).unwrap();
            // We want to read at most `count` bytes. We are sure that `count` is not negative
            // because it was a target's `usize`. Also we are sure that its smaller than
            // `usize::max_value()` because it is a host's `isize`.
            let mut bytes = vec![0; count as usize];
            let result = handle
                .file
                .read(&mut bytes)
                .map(|c| i64::try_from(c).unwrap());

            match result {
                Ok(read_bytes) => {
                    // If reading to `bytes` did not fail, we write those bytes to the buffer.
                    this.memory.write_bytes(buf, bytes)?;
                    Ok(read_bytes)
                }
                Err(e) => {
                    this.set_last_error_from_io_error(e)?;
                    Ok(-1)
                }
            }
        } else {
            this.handle_not_found()
        }
    }

    fn write(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("write")?;

        let ptr_size = this.pointer_size().bits();

        let count = this
            .read_scalar(count_op)?
            .to_machine_usize(&*this.tcx)?
            .min(1 << (ptr_size - 1));
        // Writing zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?;
            let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap());
            this.try_unwrap_io_result(result)
        } else {
            this.handle_not_found()
        }
    }

    fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("unlink")?;

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let result = remove_file(path).map(|_| 0);

        this.try_unwrap_io_result(result)
    }

    /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets
    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
    /// types (like `read`, that returns an `i64`).
    fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
        let this = self.eval_context_mut();
        let ebadf = this.eval_libc("EBADF")?;
        this.set_last_error(ebadf)?;
        Ok((-1).into())
    }
}
<commit_msg>Cap `count` twice<commit_after>use std::collections::HashMap;
use std::convert::TryFrom;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};

use rustc::ty::layout::Size;

use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Debug)]
pub struct FileHandle {
    file: File,
}

pub struct FileHandler {
    handles: HashMap<i32, FileHandle>,
    low: i32,
}

impl Default for FileHandler {
    fn default() -> Self {
        FileHandler {
            handles: Default::default(),
            // 0, 1 and 2 are reserved for stdin, stdout and stderr.
            low: 3,
        }
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn open(
        &mut self,
        path_op: OpTy<'tcx, Tag>,
        flag_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("open")?;

        let flag = this.read_scalar(flag_op)?.to_i32()?;

        let mut options = OpenOptions::new();

        let o_rdonly = this.eval_libc_i32("O_RDONLY")?;
        let o_wronly = this.eval_libc_i32("O_WRONLY")?;
        let o_rdwr = this.eval_libc_i32("O_RDWR")?;
        // The first two bits of the flag correspond to the access mode in linux, macOS and
        // windows. We need to check that in fact the access mode flags for the current platform
        // only use these two bits, otherwise we are in an unsupported platform and should error.
        if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
            throw_unsup_format!("Access mode flags on this platform are unsupported");
        }
        // Now we check the access mode
        let access_mode = flag & 0b11;

        if access_mode == o_rdonly {
            options.read(true);
        } else if access_mode == o_wronly {
            options.write(true);
        } else if access_mode == o_rdwr {
            options.read(true).write(true);
        } else {
            throw_unsup_format!("Unsupported access mode {:#x}", access_mode);
        }
        // We need to check that there aren't unsupported options in `flag`. For this we try to
        // reproduce the content of `flag` in the `mirror` variable using only the supported
        // options.
        let mut mirror = access_mode;

        let o_append = this.eval_libc_i32("O_APPEND")?;
        if flag & o_append != 0 {
            options.append(true);
            mirror |= o_append;
        }
        let o_trunc = this.eval_libc_i32("O_TRUNC")?;
        if flag & o_trunc != 0 {
            options.truncate(true);
            mirror |= o_trunc;
        }
        let o_creat = this.eval_libc_i32("O_CREAT")?;
        if flag & o_creat != 0 {
            options.create(true);
            mirror |= o_creat;
        }
        let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?;
        if flag & o_cloexec != 0 {
            // We do not need to do anything for this flag because `std` already sets it.
            // (Technically we do not support *not* setting this flag, but we ignore that.)
            mirror |= o_cloexec;
        }
        // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
        // then we throw an error.
        if flag != mirror {
            throw_unsup_format!("unsupported flags {:#x}", flag & !mirror);
        }

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let fd = options.open(path).map(|file| {
            let mut fh = &mut this.machine.file_handler;
            fh.low += 1;
            fh.handles.insert(fh.low, FileHandle { file }).unwrap_none();
            fh.low
        });

        this.try_unwrap_io_result(fd)
    }

    fn fcntl(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        cmd_op: OpTy<'tcx, Tag>,
        _arg1_op: Option<OpTy<'tcx, Tag>>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("fcntl")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let cmd = this.read_scalar(cmd_op)?.to_i32()?;
        // We only support getting the flags for a descriptor.
        if cmd == this.eval_libc_i32("F_GETFD")? {
            // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
            // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
            // always sets this flag when opening a file. However we still need to check that the
            // file itself is open.
            if this.machine.file_handler.handles.contains_key(&fd) {
                Ok(this.eval_libc_i32("FD_CLOEXEC")?)
            } else {
                this.handle_not_found()
            }
        } else {
            throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
        }
    }

    fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("close")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;

        if let Some(handle) = this.machine.file_handler.handles.remove(&fd) {
            // `File::sync_all` does the checks that are done when closing a file. We do this to
            // to handle possible errors correctly.
            let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32));
            // Now we actually close the file.
            drop(handle);
            // And return the result.
            result
        } else {
            this.handle_not_found()
        }
    }

    fn read(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("read")?;

        let ptr_size = this.pointer_size().bits();

        // We cap the number of read bytes to the largest value that we are able to fit in both the
        // host's and target's `isize`.
        let count = this
            .read_scalar(count_op)?
            .to_machine_usize(&*this.tcx)?
            .min(1 << (ptr_size - 1))
            .min(isize::max_value() as u64);
        // Reading zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            // This can never fail because `count` was capped to be smaller than
            // `isize::max_value()`.
            let count = isize::try_from(count).unwrap();
            // We want to read at most `count` bytes. We are sure that `count` is not negative
            // because it was a target's `usize`. Also we are sure that its smaller than
            // `usize::max_value()` because it is a host's `isize`.
            let mut bytes = vec![0; count as usize];
            let result = handle
                .file
                .read(&mut bytes)
                // `File::read` never returns a value larger than `i64::max_value()`, so this
                // unwrap cannot fail.
                .map(|c| i64::try_from(c).unwrap());

            match result {
                Ok(read_bytes) => {
                    // If reading to `bytes` did not fail, we write those bytes to the buffer.
                    this.memory.write_bytes(buf, bytes)?;
                    Ok(read_bytes)
                }
                Err(e) => {
                    this.set_last_error_from_io_error(e)?;
                    Ok(-1)
                }
            }
        } else {
            this.handle_not_found()
        }
    }

    fn write(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("write")?;

        let ptr_size = this.pointer_size().bits();

        // We cap the number of read bytes to the largest value that we are able to fit in both the
        // host's and target's `isize`.
        let count = this
            .read_scalar(count_op)?
            .to_machine_usize(&*this.tcx)?
            .min(1 << (ptr_size - 1))
            .min(isize::max_value() as u64);
        // Writing zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?;
            let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap());
            this.try_unwrap_io_result(result)
        } else {
            this.handle_not_found()
        }
    }

    fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("unlink")?;

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let result = remove_file(path).map(|_| 0);

        this.try_unwrap_io_result(result)
    }

    /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets
    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
    /// types (like `read`, that returns an `i64`).
    fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
        let this = self.eval_context_mut();
        let ebadf = this.eval_libc("EBADF")?;
        this.set_last_error(ebadf)?;
        Ok((-1).into())
    }
}
<|endoftext|>


<commit_before>use action;
use settings;
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use object;
use Object = object::Object;
use text;
use game_state;

pub struct SnakeApp {
    settings: Settings,
    // Tells where the surface is.
    surface_y: Option<f64>,
    game_state: Option<game_state::GameState>,
    camera_pos: Option<[f64, ..2]>,
    camera_follow_percentage: Option<f64>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        // Get camera coordinates.
        let (cam_x, cam_y) = if self.camera_pos.is_some() {
                let camera_pos = self.camera_pos.unwrap();
                (camera_pos[0], camera_pos[1])
            } else { (0.0, 0.0) };

        // Render surface.
        let surface_y = self.surface_y.unwrap();
        c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(settings::BLUE).fill(gl);

        // Render round rectangle around bars.
        let bar_bgh = settings::BAR_BACKGROUND_HEIGHT;
        let bar_color = settings::BAR_BACKGROUND_COLOR;
        c.rect(-1.0, 1.0 - bar_bgh, 2.0, bar_bgh).round(0.1).color(bar_color).fill(gl);

        // Render objects.
        let cam = &c.trans(-cam_x, -cam_y);
        for obj in self.objects.iter() {
            obj.render(cam, c, gl);
        }

        match self.game_state.unwrap() {
            game_state::Win => {
                let pos = settings::YOU_WIN_POS;
                text::text("you win", &c.flip_v_local().zoom(0.0025).trans(pos[0], pos[1]).color(settings::YOU_WIN_TEXT_COLOR), gl);
            },
            game_state::Loose => {

            },
            game_state::Play => {

            },
        }

        // TEST
        // text::text("restart", &c.flip_v_local().zoom(0.001).color(settings::BLACK), gl);
    }

    fn update(&mut self, dt: f64) {
        self.update_objects(dt);
        self.win();
        self.show_blood();
        self.follow_player(dt);
    }

    fn load(&mut self) {
        self.camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
        self.camera_pos = Some(settings::INITIAL_CAMERA_POS);
        self.surface_y = Some(settings::SURFACE_Y);
        self.game_state = Some(settings::INITIAL_GAME_STATE);

        // Add player.
        self.objects.push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            [settings::PLAYER_SPEED_LEFT, settings::PLAYER_SPEED_RIGHT],
            [settings::PLAYER_SPEED_UP, settings::PLAYER_SPEED_DOWN]
        ));
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add sharks.
        self.add_sharks();
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        if self.game_state.unwrap() != game_state::Play { return; }

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            camera_pos: None,
            camera_follow_percentage: None,
            settings: Settings::new(exit_on_esc, background_color),
            game_state: None,
            surface_y: None,
            objects: Vec::new(),
            player_index: None,
            blood_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        self.objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(self.objects.len() - 1);
    }

    pub fn add_sharks(&mut self) {
        self.objects.push(Object::shark(settings::SHARK_1_POS, settings::SHARK_1_SETTINGS));
    }

    fn follow_player(&mut self, dt: f64) {
        if self.camera_pos.is_none() { return; }
        // Make camera follow player.
        let camera_pos = self.camera_pos.unwrap();
        let camera_follow_percentage = self.camera_follow_percentage.unwrap();
        let player_pos = self.player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        self.camera_pos = Some([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    fn show_blood(&mut self) {
        if self.blood_bar_index == None { return; }
        // Show blood.
        let player_blood = self.player_blood();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let blood_bar = self.objects.get_mut(blood_bar_index);
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn win(&mut self) {
        let player_pos = self.player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= self.surface_y.unwrap() {
            self.game_state = Some(game_state::Win);
            return;
        }
    }

    fn update_objects(&mut self, dt: f64) {
        if self.game_state.unwrap() != game_state::Play { return; }

        // Update states of objects.
        let player_pos = self.player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in self.objects.mut_iter() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Decrease the players life with attacks.
        let blood = self.player_blood();
        self.set_player_blood(blood - attack_damage);
    }

    fn player_pos(&self) -> [f64, ..2] {
        let player_index = self.player_index.unwrap();
        self.objects.get(player_index).pos
    }

    fn player_blood(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        self.objects.get(player_index).blood().unwrap()
    }

    fn set_player_blood(&mut self, val: f64) {
        let player_index = self.player_index.unwrap();
        *self.objects.get_mut(player_index).blood_mut().unwrap() = val;
    }
}

<commit_msg>Added restart function<commit_after>use action;
use settings;
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use object;
use Object = object::Object;
use text;
use game_state;

pub struct SnakeApp {
    settings: Settings,
    // Tells where the surface is.
    surface_y: Option<f64>,
    game_state: Option<game_state::GameState>,
    camera_pos: Option<[f64, ..2]>,
    camera_follow_percentage: Option<f64>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        // Get camera coordinates.
        let (cam_x, cam_y) = if self.camera_pos.is_some() {
                let camera_pos = self.camera_pos.unwrap();
                (camera_pos[0], camera_pos[1])
            } else { (0.0, 0.0) };

        // Render surface.
        let surface_y = self.surface_y.unwrap();
        c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(settings::BLUE).fill(gl);

        // Render round rectangle around bars.
        let bar_bgh = settings::BAR_BACKGROUND_HEIGHT;
        let bar_color = settings::BAR_BACKGROUND_COLOR;
        c.rect(-1.0, 1.0 - bar_bgh, 2.0, bar_bgh).round(0.1).color(bar_color).fill(gl);

        // Render objects.
        let cam = &c.trans(-cam_x, -cam_y);
        for obj in self.objects.iter() {
            obj.render(cam, c, gl);
        }

        match self.game_state.unwrap() {
            game_state::Win => {
                let pos = settings::YOU_WIN_POS;
                text::text("you win", &c.flip_v_local().zoom(0.0025).trans(pos[0], pos[1]).color(settings::YOU_WIN_TEXT_COLOR), gl);
            },
            game_state::Loose => {

            },
            game_state::Play => {

            },
        }

        // TEST
        // text::text("restart", &c.flip_v_local().zoom(0.001).color(settings::BLACK), gl);
    }

    fn update(&mut self, dt: f64) {
        self.update_objects(dt);
        self.win();
        self.show_blood();
        self.follow_player(dt);
    }

    fn load(&mut self) {
        self.camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
        self.camera_pos = Some(settings::INITIAL_CAMERA_POS);
        self.surface_y = Some(settings::SURFACE_Y);
        self.game_state = Some(settings::INITIAL_GAME_STATE);

        // Add player.
        self.objects.push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            [settings::PLAYER_SPEED_LEFT, settings::PLAYER_SPEED_RIGHT],
            [settings::PLAYER_SPEED_UP, settings::PLAYER_SPEED_DOWN]
        ));
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add sharks.
        self.add_sharks();
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        if self.game_state.unwrap() != game_state::Play { return; }

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            camera_pos: None,
            camera_follow_percentage: None,
            settings: Settings::new(exit_on_esc, background_color),
            game_state: None,
            surface_y: None,
            objects: Vec::new(),
            player_index: None,
            blood_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        self.objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(self.objects.len() - 1);
    }

    pub fn add_sharks(&mut self) {
        self.objects.push(Object::shark(settings::SHARK_1_POS, settings::SHARK_1_SETTINGS));
    }

    fn follow_player(&mut self, dt: f64) {
        if self.camera_pos.is_none() { return; }
        // Make camera follow player.
        let camera_pos = self.camera_pos.unwrap();
        let camera_follow_percentage = self.camera_follow_percentage.unwrap();
        let player_pos = self.player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        self.camera_pos = Some([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    fn show_blood(&mut self) {
        if self.blood_bar_index == None { return; }
        // Show blood.
        let player_blood = self.player_blood();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let blood_bar = self.objects.get_mut(blood_bar_index);
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn win(&mut self) {
        let player_pos = self.player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= self.surface_y.unwrap() {
            self.game_state = Some(game_state::Win);
            return;
        }
    }

    fn restart(&mut self) {
        *self = SnakeApp::new();
        self.load();
    }

    fn update_objects(&mut self, dt: f64) {
        if self.game_state.unwrap() != game_state::Play { return; }

        // Update states of objects.
        let player_pos = self.player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in self.objects.mut_iter() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Decrease the players life with attacks.
        let blood = self.player_blood();
        self.set_player_blood(blood - attack_damage);
    }

    fn player_pos(&self) -> [f64, ..2] {
        let player_index = self.player_index.unwrap();
        self.objects.get(player_index).pos
    }

    fn player_blood(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        self.objects.get(player_index).blood().unwrap()
    }

    fn set_player_blood(&mut self, val: f64) {
        let player_index = self.player_index.unwrap();
        *self.objects.get_mut(player_index).blood_mut().unwrap() = val;
    }
}

<|endoftext|>


<commit_before><commit_msg>Implement BxDF::sample_f()<commit_after><|endoftext|>


<commit_before>pub struct Error {
  code: i32,
  string: &'static str
}

impl Error {
  pub fn new(err: i32) -> Error {
    Error { code: err, string: Error::error_to_string(err) }
  }

  // TODO: Finish for all errors.
  pub fn error_to_string(err: i32) -> &'static str {
    match err {
      MPI_SUCCESS => "SUCCESS",
      MPI_ERR_BUFFER => "ERR BUFFER",
      MPI_ERR_COMM => "ERR COMM",
      MPI_ERR_RANK => "ERR RANK",
      _ => "ERR OTHER"
    }
  }
}

pub const MPI_SUCCESS: i32 = 0;
pub const MPI_ERR_BUFFER: i32 = 1;
pub const MPI_ERR_COUNT: i32 = 2;
pub const MPI_ERR_TYPE: i32 = 3;
pub const MPI_ERR_TAG: i32 = 4;
pub const MPI_ERR_COMM: i32 = 5;
pub const MPI_ERR_RANK: i32 = 6;
pub const MPI_ERR_REQUEST: i32 = 7;
pub const MPI_ERR_ROOT: i32 = 8;
pub const MPI_ERR_GROUP: i32 = 9;
pub const MPI_ERR_OP: i32 = 10;
pub const MPI_ERR_TOPOLOGY: i32 = 11;
pub const MPI_ERR_DIMS: i32 = 12;
pub const MPI_ERR_ARG: i32 = 13;
pub const MPI_ERR_UNKNOWN: i32 = 14;
pub const MPI_ERR_TRUNCATE: i32 = 15;
pub const MPI_ERR_OTHER: i32 = 16;
pub const MPI_ERR_INTERN: i32 = 17;
pub const MPI_ERR_IN_STATUS: i32 = 18;
pub const MPI_ERR_PENDING: i32 = 19;
pub const MPI_ERR_ACCESS: i32 = 20;
pub const MPI_ERR_AMODE: i32 = 21;
pub const MPI_ERR_ASSERT: i32 = 22;
pub const MPI_ERR_BAD_FILE: i32 = 23;
pub const MPI_ERR_BASE: i32 = 24;
pub const MPI_ERR_CONVERSION: i32 = 25;
pub const MPI_ERR_DISP: i32 = 26;
pub const MPI_ERR_DUP_DATAREP: i32 = 27;
pub const MPI_ERR_FILE_EXISTS: i32 = 28;
pub const MPI_ERR_FILE_IN_USE: i32 = 29;
pub const MPI_ERR_FILE: i32 = 30;
pub const MPI_ERR_INFO_KEY: i32 = 31;
pub const MPI_ERR_INFO_NOKEY: i32 = 32;
pub const MPI_ERR_INFO_VALUE: i32 = 33;
pub const MPI_ERR_INFO: i32 = 34;
pub const MPI_ERR_IO: i32 = 35;
pub const MPI_ERR_KEYVAL: i32 = 36;
pub const MPI_ERR_LOCKTYPE: i32 = 37;
pub const MPI_ERR_NAME: i32 = 38;
pub const MPI_ERR_NO_MEM: i32 = 39;
pub const MPI_ERR_NOT_SAME: i32 = 40;
pub const MPI_ERR_NO_SPACE: i32 = 41;
pub const MPI_ERR_NO_SUCH_FILE: i32 = 42;
pub const MPI_ERR_PORT: i32 = 43;
pub const MPI_ERR_QUOTA: i32 = 44;
pub const MPI_ERR_READ_ONLY: i32 = 45;
pub const MPI_ERR_RMA_CONFLICT: i32 = 46;
pub const MPI_ERR_RMA_SYNC: i32 = 47;
pub const MPI_ERR_SERVICE: i32 = 48;
pub const MPI_ERR_SIZE: i32 = 49;
pub const MPI_ERR_SPAWN: i32 = 50;
pub const MPI_ERR_UNSUPPORTED_DATAREP: i32 = 51;
pub const MPI_ERR_UNSUPPORTED_OPERATION: i32 = 52;
pub const MPI_ERR_WIN: i32 = 53;
pub const MPI_T_ERR_MEMORY: i32 = 54;
pub const MPI_T_ERR_NOT_INITIALIZED: i32 = 55;
pub const MPI_T_ERR_CANNOT_INIT: i32 = 56;
pub const MPI_T_ERR_INVALID_INDEX: i32 = 57;
pub const MPI_T_ERR_INVALID_ITEM: i32 = 58;
pub const MPI_T_ERR_INVALID_HANDLE: i32 = 59;
pub const MPI_T_ERR_OUT_OF_HANDLES: i32 = 60;
pub const MPI_T_ERR_OUT_OF_SESSIONS: i32 = 61;
pub const MPI_T_ERR_INVALID_SESSION: i32 = 62;
pub const MPI_T_ERR_CVAR_SET_NOT_NOW: i32 = 63;
pub const MPI_T_ERR_CVAR_SET_NEVER: i32 = 64;
pub const MPI_T_ERR_PVAR_NO_STARTSTOP: i32 = 65;
pub const MPI_T_ERR_PVAR_NO_WRITE: i32 = 66;
pub const MPI_T_ERR_PVAR_NO_ATOMIC: i32 = 67;
pub const MPI_ERR_RMA_RANGE: i32 = 68;
pub const MPI_ERR_RMA_ATTACH: i32 = 69;
pub const MPI_ERR_RMA_FLAVOR: i32 = 70;
pub const MPI_ERR_RMA_SHARED: i32 = 71;
pub const MPI_ERR_LASTCODE: i32 = MPI_ERR_RMA_SHARED;
pub const MPI_ERR_SYSRESOURCE: i32 = -2;
<commit_msg>Make Error fields public.<commit_after>pub struct Error {
  pub code: i32,
  pub string: &'static str
}

impl Error {
  pub fn new(err: i32) -> Error {
    Error { code: err, string: Error::error_to_string(err) }
  }

  // TODO: Finish for all errors.
  pub fn error_to_string(err: i32) -> &'static str {
    match err {
      MPI_SUCCESS => "SUCCESS",
      MPI_ERR_BUFFER => "ERR BUFFER",
      MPI_ERR_COMM => "ERR COMM",
      MPI_ERR_RANK => "ERR RANK",
      _ => "ERR OTHER"
    }
  }
}

pub const MPI_SUCCESS: i32 = 0;
pub const MPI_ERR_BUFFER: i32 = 1;
pub const MPI_ERR_COUNT: i32 = 2;
pub const MPI_ERR_TYPE: i32 = 3;
pub const MPI_ERR_TAG: i32 = 4;
pub const MPI_ERR_COMM: i32 = 5;
pub const MPI_ERR_RANK: i32 = 6;
pub const MPI_ERR_REQUEST: i32 = 7;
pub const MPI_ERR_ROOT: i32 = 8;
pub const MPI_ERR_GROUP: i32 = 9;
pub const MPI_ERR_OP: i32 = 10;
pub const MPI_ERR_TOPOLOGY: i32 = 11;
pub const MPI_ERR_DIMS: i32 = 12;
pub const MPI_ERR_ARG: i32 = 13;
pub const MPI_ERR_UNKNOWN: i32 = 14;
pub const MPI_ERR_TRUNCATE: i32 = 15;
pub const MPI_ERR_OTHER: i32 = 16;
pub const MPI_ERR_INTERN: i32 = 17;
pub const MPI_ERR_IN_STATUS: i32 = 18;
pub const MPI_ERR_PENDING: i32 = 19;
pub const MPI_ERR_ACCESS: i32 = 20;
pub const MPI_ERR_AMODE: i32 = 21;
pub const MPI_ERR_ASSERT: i32 = 22;
pub const MPI_ERR_BAD_FILE: i32 = 23;
pub const MPI_ERR_BASE: i32 = 24;
pub const MPI_ERR_CONVERSION: i32 = 25;
pub const MPI_ERR_DISP: i32 = 26;
pub const MPI_ERR_DUP_DATAREP: i32 = 27;
pub const MPI_ERR_FILE_EXISTS: i32 = 28;
pub const MPI_ERR_FILE_IN_USE: i32 = 29;
pub const MPI_ERR_FILE: i32 = 30;
pub const MPI_ERR_INFO_KEY: i32 = 31;
pub const MPI_ERR_INFO_NOKEY: i32 = 32;
pub const MPI_ERR_INFO_VALUE: i32 = 33;
pub const MPI_ERR_INFO: i32 = 34;
pub const MPI_ERR_IO: i32 = 35;
pub const MPI_ERR_KEYVAL: i32 = 36;
pub const MPI_ERR_LOCKTYPE: i32 = 37;
pub const MPI_ERR_NAME: i32 = 38;
pub const MPI_ERR_NO_MEM: i32 = 39;
pub const MPI_ERR_NOT_SAME: i32 = 40;
pub const MPI_ERR_NO_SPACE: i32 = 41;
pub const MPI_ERR_NO_SUCH_FILE: i32 = 42;
pub const MPI_ERR_PORT: i32 = 43;
pub const MPI_ERR_QUOTA: i32 = 44;
pub const MPI_ERR_READ_ONLY: i32 = 45;
pub const MPI_ERR_RMA_CONFLICT: i32 = 46;
pub const MPI_ERR_RMA_SYNC: i32 = 47;
pub const MPI_ERR_SERVICE: i32 = 48;
pub const MPI_ERR_SIZE: i32 = 49;
pub const MPI_ERR_SPAWN: i32 = 50;
pub const MPI_ERR_UNSUPPORTED_DATAREP: i32 = 51;
pub const MPI_ERR_UNSUPPORTED_OPERATION: i32 = 52;
pub const MPI_ERR_WIN: i32 = 53;
pub const MPI_T_ERR_MEMORY: i32 = 54;
pub const MPI_T_ERR_NOT_INITIALIZED: i32 = 55;
pub const MPI_T_ERR_CANNOT_INIT: i32 = 56;
pub const MPI_T_ERR_INVALID_INDEX: i32 = 57;
pub const MPI_T_ERR_INVALID_ITEM: i32 = 58;
pub const MPI_T_ERR_INVALID_HANDLE: i32 = 59;
pub const MPI_T_ERR_OUT_OF_HANDLES: i32 = 60;
pub const MPI_T_ERR_OUT_OF_SESSIONS: i32 = 61;
pub const MPI_T_ERR_INVALID_SESSION: i32 = 62;
pub const MPI_T_ERR_CVAR_SET_NOT_NOW: i32 = 63;
pub const MPI_T_ERR_CVAR_SET_NEVER: i32 = 64;
pub const MPI_T_ERR_PVAR_NO_STARTSTOP: i32 = 65;
pub const MPI_T_ERR_PVAR_NO_WRITE: i32 = 66;
pub const MPI_T_ERR_PVAR_NO_ATOMIC: i32 = 67;
pub const MPI_ERR_RMA_RANGE: i32 = 68;
pub const MPI_ERR_RMA_ATTACH: i32 = 69;
pub const MPI_ERR_RMA_FLAVOR: i32 = 70;
pub const MPI_ERR_RMA_SHARED: i32 = 71;
pub const MPI_ERR_LASTCODE: i32 = MPI_ERR_RMA_SHARED;
pub const MPI_ERR_SYSRESOURCE: i32 = -2;
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ProgramHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    assert!(gl_id != 0);

    ProgramHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from(
    _gl: &'a GLContextExistence,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };

    assert!(gl_id != 0);

    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("error compiling 0x{:x} shader: {}", typ, str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }

    ShaderHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> Shader<'a> {
  pub fn new<T: Iterator<(String, GLenum)>>(
    gl: &'a GLContextExistence,
    mut shader_components: T,
  ) -> Shader<'a> {
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe {
        gl::AttachShader(handle.gl_id, s.gl_id);
      }
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
      lifetime: ContravariantLifetime,
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location(
    &mut self,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    // TODO: This shouldn't require a clone.
    match self.uniforms.entry(s_name.clone()) {
      Entry::Occupied(entry) => *entry.get(),
      Entry::Vacant(entry) => {
        let c_name = name.to_c_str();
        let p_name = c_name.as_ptr();
        let loc = unsafe {
          gl::GetUniformLocation(self.handle.gl_id, p_name)
        };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        *entry.set(loc)
      },
    }
  }
}
<commit_msg>rustup<commit_after>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ProgramHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    assert!(gl_id != 0);

    ProgramHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from(
    _gl: &'a GLContextExistence,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };

    assert!(gl_id != 0);

    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      let error_string =
        str::from_utf8(buf.as_slice())
          .unwrap_or_else(|_| panic!("ShaderInfoLog not valid utf8"));
      panic!("error compiling 0x{:x} shader: {}", typ, error_string);
    }

    ShaderHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> Shader<'a> {
  pub fn new<T: Iterator<(String, GLenum)>>(
    gl: &'a GLContextExistence,
    mut shader_components: T,
  ) -> Shader<'a> {
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe {
        gl::AttachShader(handle.gl_id, s.gl_id);
      }
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      let error_string =
        str::from_utf8(buf.as_slice())
          .unwrap_or_else(|_| panic!("ProgramInfoLog not valid utf8"));
      panic!("{}", error_string);
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
      lifetime: ContravariantLifetime,
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location(
    &mut self,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    // TODO: This shouldn't require a clone.
    match self.uniforms.entry(s_name.clone()) {
      Entry::Occupied(entry) => *entry.get(),
      Entry::Vacant(entry) => {
        let c_name = name.to_c_str();
        let p_name = c_name.as_ptr();
        let loc = unsafe {
          gl::GetUniformLocation(self.handle.gl_id, p_name)
        };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        *entry.set(loc)
      },
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;

pub use glib::signal::Inhibit;
use glib::translate::*;

use glib_ffi::{self, gboolean, gpointer};

use {
    Continue,
    ScrollType,
    SpinButton,
};

// idle_add and timeout_add fixed to the main thread

unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    callback_guard!();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    callback_guard!();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure))
    }
}

pub trait EditableSignals {
    fn connect_changed<F>(&self, changed_func: F) -> u64
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> u64
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> u64
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use Object;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::connect;
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Downcast;
    use std::slice;

    impl<T: IsA<Editable> + IsA<Object>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> u64
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self) + 'static>> =
                    Box::new(Box::new(changed_func));
                connect(self.to_glib_none().0, "changed",
                    transmute(trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> u64
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, i32, i32) + 'static>> =
                    Box::new(Box::new(delete_text_func));
                connect(self.to_glib_none().0, "delete-text",
                    transmute(delete_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> u64
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, &str, &mut i32) + 'static>> =
                    Box::new(Box::new(insert_text_func));
                connect(self.to_glib_none().0, "insert-text",
                    transmute(insert_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn trampoline<T>(this: *mut GtkEditable,
                                       f: &Box<Fn(&T) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_none(this).downcast_unchecked());
    }

    unsafe extern "C" fn delete_trampoline<T>(this: *mut GtkEditable,
                                              start_pos: c_int,
                                              end_pos: c_int,
                                              f: &Box<Fn(&T, i32, i32) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_none(this).downcast_unchecked(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T>(this: *mut GtkEditable,
                                              new_text: *mut c_char,
                                              new_text_length: c_int,
                                              position: *mut c_int,
                                              f: &Box<Fn(&T, &str, &mut i32) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_none(this).downcast_unchecked(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals {
    fn connect_change_value<F>(&self, change_value_func: F) -> u64
        where F: Fn(&SpinButton, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> u64
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> u64
        where F: Fn(&SpinButton) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> u64
        where F: Fn(&SpinButton) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> u64
        where F: Fn(&SpinButton) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::connect;
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl ::SpinButtonSignals for SpinButton {
        fn connect_change_value<F>(&self, change_value_func: F) -> u64
        where F: Fn(&SpinButton, ScrollType) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton, ScrollType) + 'static>> =
                    Box::new(Box::new(change_value_func));
                connect(self.to_glib_none().0, "change_value",
                        transmute(change_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_input<F>(&self, f: F) -> u64
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>> = Box_::new(Box_::new(f));
                connect(self.to_glib_none().0, "input",
                        transmute(input_trampoline as usize), Box_::into_raw(f) as *mut _)
            }
        }

        fn connect_output<F>(&self, output_func: F) -> u64
        where F: Fn(&SpinButton) -> Inhibit + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) -> Inhibit + 'static>> =
                    Box::new(Box::new(output_func));
                connect(self.to_glib_none().0, "output",
                        transmute(output_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> u64
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(value_changed_func));
                connect(self.to_glib_none().0, "value-changed",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> u64
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(wrapped_func));
                connect(self.to_glib_none().0, "wrapped",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn change_trampoline(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &Box<Fn(&SpinButton, ScrollType) + 'static>) {
        callback_guard!();
        f(&from_glib_none(this), scroll)
    }

    unsafe extern "C" fn input_trampoline(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>)
                                          -> c_int {
        callback_guard!();
        match f(&from_glib_none(this)) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline(this: *mut GtkSpinButton,
                                           f: &Box<Fn(&SpinButton) -> Inhibit + 'static>)
                                           -> gboolean {
        callback_guard!();
        f(&from_glib_none(this)).to_glib()
    }

    unsafe extern "C" fn trampoline(this: *mut GtkSpinButton,
                                    f: &Box<Fn(&SpinButton) + 'static>) {
        callback_guard!();
        f(&from_glib_none(this))
    }
}
<commit_msg>Now use SourceId<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;

pub use glib::signal::Inhibit;
use glib::SourceId;
use glib::translate::*;

use glib_ffi::{self, gboolean, gpointer};

use {
    Continue,
    ScrollType,
    SpinButton,
};

// idle_add and timeout_add fixed to the main thread

unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    callback_guard!();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    callback_guard!();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn idle_add<F>(func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(
            glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline),
                 into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

pub trait EditableSignals {
    fn connect_changed<F>(&self, changed_func: F) -> u64
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> u64
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> u64
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use Object;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::connect;
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Downcast;
    use std::slice;

    impl<T: IsA<Editable> + IsA<Object>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> u64
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self) + 'static>> =
                    Box::new(Box::new(changed_func));
                connect(self.to_glib_none().0, "changed",
                    transmute(trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> u64
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, i32, i32) + 'static>> =
                    Box::new(Box::new(delete_text_func));
                connect(self.to_glib_none().0, "delete-text",
                    transmute(delete_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> u64
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, &str, &mut i32) + 'static>> =
                    Box::new(Box::new(insert_text_func));
                connect(self.to_glib_none().0, "insert-text",
                    transmute(insert_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn trampoline<T>(this: *mut GtkEditable,
                                       f: &Box<Fn(&T) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_none(this).downcast_unchecked());
    }

    unsafe extern "C" fn delete_trampoline<T>(this: *mut GtkEditable,
                                              start_pos: c_int,
                                              end_pos: c_int,
                                              f: &Box<Fn(&T, i32, i32) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_none(this).downcast_unchecked(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T>(this: *mut GtkEditable,
                                              new_text: *mut c_char,
                                              new_text_length: c_int,
                                              position: *mut c_int,
                                              f: &Box<Fn(&T, &str, &mut i32) + 'static>)
    where T: IsA<Editable> {
        callback_guard!();
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_none(this).downcast_unchecked(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals {
    fn connect_change_value<F>(&self, change_value_func: F) -> u64
        where F: Fn(&SpinButton, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> u64
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> u64
        where F: Fn(&SpinButton) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> u64
        where F: Fn(&SpinButton) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> u64
        where F: Fn(&SpinButton) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::connect;
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl ::SpinButtonSignals for SpinButton {
        fn connect_change_value<F>(&self, change_value_func: F) -> u64
        where F: Fn(&SpinButton, ScrollType) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton, ScrollType) + 'static>> =
                    Box::new(Box::new(change_value_func));
                connect(self.to_glib_none().0, "change_value",
                        transmute(change_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_input<F>(&self, f: F) -> u64
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>> = Box_::new(Box_::new(f));
                connect(self.to_glib_none().0, "input",
                        transmute(input_trampoline as usize), Box_::into_raw(f) as *mut _)
            }
        }

        fn connect_output<F>(&self, output_func: F) -> u64
        where F: Fn(&SpinButton) -> Inhibit + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) -> Inhibit + 'static>> =
                    Box::new(Box::new(output_func));
                connect(self.to_glib_none().0, "output",
                        transmute(output_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> u64
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(value_changed_func));
                connect(self.to_glib_none().0, "value-changed",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> u64
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(wrapped_func));
                connect(self.to_glib_none().0, "wrapped",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn change_trampoline(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &Box<Fn(&SpinButton, ScrollType) + 'static>) {
        callback_guard!();
        f(&from_glib_none(this), scroll)
    }

    unsafe extern "C" fn input_trampoline(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>)
                                          -> c_int {
        callback_guard!();
        match f(&from_glib_none(this)) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline(this: *mut GtkSpinButton,
                                           f: &Box<Fn(&SpinButton) -> Inhibit + 'static>)
                                           -> gboolean {
        callback_guard!();
        f(&from_glib_none(this)).to_glib()
    }

    unsafe extern "C" fn trampoline(this: *mut GtkSpinButton,
                                    f: &Box<Fn(&SpinButton) + 'static>) {
        callback_guard!();
        f(&from_glib_none(this))
    }
}
<|endoftext|>


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

pub mod simple;
pub mod websocket;

pub trait Frame {
    fn to_bytes(&self) -> Vec<u8>;
    fn payload(&self) -> Vec<u8>;
    fn len_as_vec(&self) -> usize;
}

pub trait FrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>>;
}
<commit_msg>Sync and Send to Frame requirements.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

pub mod simple;
pub mod websocket;

pub trait Frame: Sync + Send {
    fn to_bytes(&self) -> Vec<u8>;
    fn payload(&self) -> Vec<u8>;
    fn len_as_vec(&self) -> usize;
}

pub trait FrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>>;
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};

use stack;
use context::Context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<Input: Send, Output: Send, Stack: stack::Stack> {
  state:   State,
  context: Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Generator<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(env as *mut (Yielder<Input, Output, Stack>, F));
      let data = Context::swap(yielder.context, yielder.context, 0);
      // See the second half of Yielder::suspend_bare.
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      yielder.context = new_context as *mut Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: Context::new(stack, generator_wrapper::<Input, Output, Stack, F>),
      phantom: (PhantomData, PhantomData)
    };

    // Transfer environment to the callee.
    let mut env = (Yielder::new(&mut generator.context), f);
    Context::swap(&mut generator.context, &generator.context,
                  &mut env as *mut (Yielder<Input, Output, Stack>, F) as usize);
    mem::forget(env);

    generator
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let mut data_in = (&mut self.context as *mut Context<Stack>, input);
          let data_out =
            ptr::read(Context::swap(&mut self.context, &self.context,
                                    &mut data_in as *mut (*mut Context<Stack>, Input)  as usize)
                      as *mut Option<Output>);
          mem::forget(data_in);
          data_out
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send, Stack: stack::Stack> {
  context: *mut Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Yielder<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  fn new(context: *mut Context<Stack>) -> Yielder<Input, Output, Stack> {
    Yielder {
      context: context,
      phantom: (PhantomData, PhantomData)
    }
  }

  #[inline(always)]
  fn suspend_bare(&mut self, mut val: Option<Output>) -> Input {
    unsafe {
      let data = Context::swap(self.context, self.context,
                               &mut val as *mut Option<Output> as usize);
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context;
      // However, between this point and the next time we enter suspend_bare
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
      input
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&mut self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<Output, Stack> Iterator for Generator<(), Output, Stack>
    where Output: Send, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<commit_msg>don't drop yielded values in the generator<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};

use stack;
use context::Context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<Input: Send, Output: Send, Stack: stack::Stack> {
  state:   State,
  context: Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Generator<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  /// Creates a new generator.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(env as *mut (Yielder<Input, Output, Stack>, F));
      let data = Context::swap(yielder.context, yielder.context, 0);
      // See the second half of Yielder::suspend_bare.
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      yielder.context = new_context as *mut Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: Context::new(stack, generator_wrapper::<Input, Output, Stack, F>),
      phantom: (PhantomData, PhantomData)
    };

    // Transfer environment to the callee.
    let mut env = (Yielder::new(&mut generator.context), f);
    Context::swap(&mut generator.context, &generator.context,
                  &mut env as *mut (Yielder<Input, Output, Stack>, F) as usize);
    mem::forget(env);

    generator
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let mut data_in = (&mut self.context as *mut Context<Stack>, input);
          let data_out =
            ptr::read(Context::swap(&mut self.context, &self.context,
                                    &mut data_in as *mut (*mut Context<Stack>, Input)  as usize)
                      as *mut Option<Output>);
          mem::forget(data_in);
          data_out
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send, Stack: stack::Stack> {
  context: *mut Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Yielder<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  fn new(context: *mut Context<Stack>) -> Yielder<Input, Output, Stack> {
    Yielder {
      context: context,
      phantom: (PhantomData, PhantomData)
    }
  }

  #[inline(always)]
  fn suspend_bare(&mut self, mut val: Option<Output>) -> Input {
    unsafe {
      let data = Context::swap(self.context, self.context,
                               &mut val as *mut Option<Output> as usize);
      mem::forget(val);
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context;
      // However, between this point and the next time we enter suspend_bare
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
      input
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&mut self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<Output, Stack> Iterator for Generator<(), Output, Stack>
    where Output: Send, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<|endoftext|>