<commit_before>/* 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/. */

use byteorder::{LittleEndian, WriteBytesExt};
use display_list::{AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList};
use display_list::{BuiltDisplayListDescriptor};
use euclid::{Point2D, Size2D};
use ipc_channel::ipc::{self, IpcBytesSender, IpcSender};
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use stacking_context::StackingContext;
use std::cell::Cell;
use types::{ColorF, DisplayListId, Epoch, FontKey, StackingContextId};
use types::{ImageKey, ImageFormat, NativeFontHandle, PipelineId};
use webgl::{WebGLContextId, WebGLCommand};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct IdNamespace(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ResourceId(pub u32);

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum ScrollEventPhase {
    /// The user started scrolling.
    Start,
    /// The user performed a scroll. The Boolean flag indicates whether the user's fingers are
    /// down, if a touchpad is in use. (If false, the event is a touchpad fling.)
    Move(bool),
    /// The user ended scrolling.
    End,
}

#[derive(Serialize, Deserialize)]
pub enum ApiMsg {
    AddRawFont(FontKey, Vec<u8>),
    AddNativeFont(FontKey, NativeFontHandle),
    AddImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    UpdateImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    CloneApi(IpcSender<IdNamespace>),
    /// Supplies a new frame to WebRender.
    ///
    /// The first `StackingContextId` describes the root stacking context. The actual stacking
    /// contexts are supplied as the sixth parameter, while the display lists that make up those
    /// stacking contexts are supplied as the seventh parameter.
    ///
    /// After receiving this message, WebRender will read the display lists, followed by the
    /// auxiliary lists, from the payload channel.
    SetRootStackingContext(StackingContextId,
                           ColorF,
                           Epoch,
                           PipelineId,
                           Size2D<f32>,
                           Vec<(StackingContextId, StackingContext)>,
                           Vec<(DisplayListId, BuiltDisplayListDescriptor)>,
                           AuxiliaryListsDescriptor),
    SetRootPipeline(PipelineId),
    Scroll(Point2D<f32>, Point2D<f32>, ScrollEventPhase),
    TickScrollingBounce,
    TranslatePointToLayerSpace(Point2D<f32>, IpcSender<Point2D<f32>>),
    RequestWebGLContext(Size2D<i32>, GLContextAttributes, IpcSender<Result<(WebGLContextId, GLLimits), String>>),
    WebGLCommand(WebGLContextId, WebGLCommand),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RenderApiSender {
    api_sender: IpcSender<ApiMsg>,
    payload_sender: IpcBytesSender,
}

impl RenderApiSender {
    pub fn new(api_sender: IpcSender<ApiMsg>, payload_sender: IpcBytesSender) -> RenderApiSender {
        RenderApiSender {
            api_sender: api_sender,
            payload_sender: payload_sender,
        }
    }

    pub fn create_api(&self) -> RenderApi {
        let RenderApiSender {
            ref api_sender,
            ref payload_sender
        } = *self;
        let (sync_tx, sync_rx) = ipc::channel().unwrap();
        let msg = ApiMsg::CloneApi(sync_tx);
        api_sender.send(msg).unwrap();
        RenderApi {
            api_sender: api_sender.clone(),
            payload_sender: payload_sender.clone(),
            id_namespace: sync_rx.recv().unwrap(),
            next_id: Cell::new(ResourceId(0)),
        }
    }
}

pub struct RenderApi {
    pub api_sender: IpcSender<ApiMsg>,
    pub payload_sender: IpcBytesSender,
    pub id_namespace: IdNamespace,
    pub next_id: Cell<ResourceId>,
}

impl RenderApi {
    pub fn clone_sender(&self) -> RenderApiSender {
        RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone())
    }

    pub fn add_raw_font(&self, bytes: Vec<u8>) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddRawFont(key, bytes);
        self.api_sender.send(msg).unwrap();
        key
    }

    pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddNativeFont(key, native_font_handle);
        self.api_sender.send(msg).unwrap();
        key
    }

    pub fn alloc_image(&self) -> ImageKey {
        let new_id = self.next_unique_id();
        ImageKey::new(new_id.0, new_id.1)
    }

    pub fn add_image(&self,
                     width: u32,
                     height: u32,
                     format: ImageFormat,
                     bytes: Vec<u8>) -> ImageKey {
        let new_id = self.next_unique_id();
        let key = ImageKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddImage(key, width, height, format, bytes);
        self.api_sender.send(msg).unwrap();
        key
    }

    // TODO: Support changing dimensions (and format) during image update?
    pub fn update_image(&self,
                        key: ImageKey,
                        width: u32,
                        height: u32,
                        format: ImageFormat,
                        bytes: Vec<u8>) {
        let msg = ApiMsg::UpdateImage(key, width, height, format, bytes);
        self.api_sender.send(msg).unwrap();
    }

    pub fn set_root_pipeline(&self, pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootPipeline(pipeline_id);
        self.api_sender.send(msg).unwrap();
    }

    /// Supplies a new frame to WebRender.
    ///
    /// Arguments:
    /// * `stacking_context_id`: The ID of the root stacking context.
    /// * `background_color`: The background color of this pipeline.
    /// * `epoch`: A monotonically increasing timestamp.
    /// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
    /// * `viewport_size`: The size of the viewport for this frame.
    /// * `stacking_contexts`: Stacking contexts used in this frame.
    /// * `display_lists`: Display lists used in this frame.
    /// * `auxiliary_lists`: Various items that the display lists and stacking contexts reference.
    pub fn set_root_stacking_context(&self,
                                     stacking_context_id: StackingContextId,
                                     background_color: ColorF,
                                     epoch: Epoch,
                                     pipeline_id: PipelineId,
                                     viewport_size: Size2D<f32>,
                                     stacking_contexts: Vec<(StackingContextId, StackingContext)>,
                                     display_lists: Vec<(DisplayListId, BuiltDisplayList)>,
                                     auxiliary_lists: AuxiliaryLists) {
        let display_list_descriptors = display_lists.iter().map(|&(display_list_id,
                                                                   ref built_display_list)| {
            (display_list_id, (*built_display_list.descriptor()).clone())
        }).collect();
        let msg = ApiMsg::SetRootStackingContext(stacking_context_id,
                                                 background_color,
                                                 epoch,
                                                 pipeline_id,
                                                 viewport_size,
                                                 stacking_contexts,
                                                 display_list_descriptors,
                                                 *auxiliary_lists.descriptor());
        self.api_sender.send(msg).unwrap();

        let mut payload = vec![];
        payload.write_u32::<LittleEndian>(stacking_context_id.0).unwrap();
        payload.write_u32::<LittleEndian>(epoch.0).unwrap();

        for &(_, ref built_display_list) in &display_lists {
            payload.extend_from_slice(built_display_list.data());
        }
        payload.extend_from_slice(auxiliary_lists.data());

        self.payload_sender.send(&payload[..]).unwrap();
    }

    pub fn scroll(&self, delta: Point2D<f32>, cursor: Point2D<f32>, phase: ScrollEventPhase) {
        let msg = ApiMsg::Scroll(delta, cursor, phase);
        self.api_sender.send(msg).unwrap();
    }

    pub fn tick_scrolling_bounce_animations(&self) {
        let msg = ApiMsg::TickScrollingBounce;
        self.api_sender.send(msg).unwrap();
    }

    pub fn translate_point_to_layer_space(&self, point: &Point2D<f32>) -> Point2D<f32> {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx);
        self.api_sender.send(msg).unwrap();
        rx.recv().unwrap()
    }

    pub fn request_webgl_context(&self, size: &Size2D<i32>, attributes: GLContextAttributes)
                                 -> Result<(WebGLContextId, GLLimits), String> {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::RequestWebGLContext(*size, attributes, tx);
        self.api_sender.send(msg).unwrap();
        rx.recv().unwrap()
    }

    pub fn send_webgl_command(&self, context_id: WebGLContextId, command: WebGLCommand) {
        let msg = ApiMsg::WebGLCommand(context_id, command);
        self.api_sender.send(msg).unwrap();
    }

    #[inline]
    pub fn next_stacking_context_id(&self) -> StackingContextId {
        let new_id = self.next_unique_id();
        StackingContextId(new_id.0, new_id.1)
    }

    #[inline]
    pub fn next_display_list_id(&self) -> DisplayListId {
        let new_id = self.next_unique_id();
        DisplayListId(new_id.0, new_id.1)
    }

    #[inline]
    fn next_unique_id(&self) -> (u32, u32) {
        let IdNamespace(namespace) = self.id_namespace;
        let ResourceId(id) = self.next_id.get();
        self.next_id.set(ResourceId(id + 1));
        (namespace, id)
    }
}

<commit_msg>Auto merge of #47 - pcwalton:pipeline-relative-events, r=pcwalton<commit_after>/* 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/. */

use byteorder::{LittleEndian, WriteBytesExt};
use display_list::{AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList};
use display_list::{BuiltDisplayListDescriptor};
use euclid::{Point2D, Size2D};
use ipc_channel::ipc::{self, IpcBytesSender, IpcSender};
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use stacking_context::StackingContext;
use std::cell::Cell;
use types::{ColorF, DisplayListId, Epoch, FontKey, StackingContextId};
use types::{ImageKey, ImageFormat, NativeFontHandle, PipelineId};
use webgl::{WebGLContextId, WebGLCommand};

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct IdNamespace(pub u32);

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ResourceId(pub u32);

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum ScrollEventPhase {
    /// The user started scrolling.
    Start,
    /// The user performed a scroll. The Boolean flag indicates whether the user's fingers are
    /// down, if a touchpad is in use. (If false, the event is a touchpad fling.)
    Move(bool),
    /// The user ended scrolling.
    End,
}

#[derive(Serialize, Deserialize)]
pub enum ApiMsg {
    AddRawFont(FontKey, Vec<u8>),
    AddNativeFont(FontKey, NativeFontHandle),
    AddImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    UpdateImage(ImageKey, u32, u32, ImageFormat, Vec<u8>),
    CloneApi(IpcSender<IdNamespace>),
    /// Supplies a new frame to WebRender.
    ///
    /// The first `StackingContextId` describes the root stacking context. The actual stacking
    /// contexts are supplied as the sixth parameter, while the display lists that make up those
    /// stacking contexts are supplied as the seventh parameter.
    ///
    /// After receiving this message, WebRender will read the display lists, followed by the
    /// auxiliary lists, from the payload channel.
    SetRootStackingContext(StackingContextId,
                           ColorF,
                           Epoch,
                           PipelineId,
                           Size2D<f32>,
                           Vec<(StackingContextId, StackingContext)>,
                           Vec<(DisplayListId, BuiltDisplayListDescriptor)>,
                           AuxiliaryListsDescriptor),
    SetRootPipeline(PipelineId),
    Scroll(Point2D<f32>, Point2D<f32>, ScrollEventPhase),
    TickScrollingBounce,
    TranslatePointToLayerSpace(Point2D<f32>, IpcSender<(Point2D<f32>, PipelineId)>),
    RequestWebGLContext(Size2D<i32>, GLContextAttributes, IpcSender<Result<(WebGLContextId, GLLimits), String>>),
    WebGLCommand(WebGLContextId, WebGLCommand),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct RenderApiSender {
    api_sender: IpcSender<ApiMsg>,
    payload_sender: IpcBytesSender,
}

impl RenderApiSender {
    pub fn new(api_sender: IpcSender<ApiMsg>, payload_sender: IpcBytesSender) -> RenderApiSender {
        RenderApiSender {
            api_sender: api_sender,
            payload_sender: payload_sender,
        }
    }

    pub fn create_api(&self) -> RenderApi {
        let RenderApiSender {
            ref api_sender,
            ref payload_sender
        } = *self;
        let (sync_tx, sync_rx) = ipc::channel().unwrap();
        let msg = ApiMsg::CloneApi(sync_tx);
        api_sender.send(msg).unwrap();
        RenderApi {
            api_sender: api_sender.clone(),
            payload_sender: payload_sender.clone(),
            id_namespace: sync_rx.recv().unwrap(),
            next_id: Cell::new(ResourceId(0)),
        }
    }
}

pub struct RenderApi {
    pub api_sender: IpcSender<ApiMsg>,
    pub payload_sender: IpcBytesSender,
    pub id_namespace: IdNamespace,
    pub next_id: Cell<ResourceId>,
}

impl RenderApi {
    pub fn clone_sender(&self) -> RenderApiSender {
        RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone())
    }

    pub fn add_raw_font(&self, bytes: Vec<u8>) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddRawFont(key, bytes);
        self.api_sender.send(msg).unwrap();
        key
    }

    pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey {
        let new_id = self.next_unique_id();
        let key = FontKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddNativeFont(key, native_font_handle);
        self.api_sender.send(msg).unwrap();
        key
    }

    pub fn alloc_image(&self) -> ImageKey {
        let new_id = self.next_unique_id();
        ImageKey::new(new_id.0, new_id.1)
    }

    pub fn add_image(&self,
                     width: u32,
                     height: u32,
                     format: ImageFormat,
                     bytes: Vec<u8>) -> ImageKey {
        let new_id = self.next_unique_id();
        let key = ImageKey::new(new_id.0, new_id.1);
        let msg = ApiMsg::AddImage(key, width, height, format, bytes);
        self.api_sender.send(msg).unwrap();
        key
    }

    // TODO: Support changing dimensions (and format) during image update?
    pub fn update_image(&self,
                        key: ImageKey,
                        width: u32,
                        height: u32,
                        format: ImageFormat,
                        bytes: Vec<u8>) {
        let msg = ApiMsg::UpdateImage(key, width, height, format, bytes);
        self.api_sender.send(msg).unwrap();
    }

    pub fn set_root_pipeline(&self, pipeline_id: PipelineId) {
        let msg = ApiMsg::SetRootPipeline(pipeline_id);
        self.api_sender.send(msg).unwrap();
    }

    /// Supplies a new frame to WebRender.
    ///
    /// Arguments:
    /// * `stacking_context_id`: The ID of the root stacking context.
    /// * `background_color`: The background color of this pipeline.
    /// * `epoch`: A monotonically increasing timestamp.
    /// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
    /// * `viewport_size`: The size of the viewport for this frame.
    /// * `stacking_contexts`: Stacking contexts used in this frame.
    /// * `display_lists`: Display lists used in this frame.
    /// * `auxiliary_lists`: Various items that the display lists and stacking contexts reference.
    pub fn set_root_stacking_context(&self,
                                     stacking_context_id: StackingContextId,
                                     background_color: ColorF,
                                     epoch: Epoch,
                                     pipeline_id: PipelineId,
                                     viewport_size: Size2D<f32>,
                                     stacking_contexts: Vec<(StackingContextId, StackingContext)>,
                                     display_lists: Vec<(DisplayListId, BuiltDisplayList)>,
                                     auxiliary_lists: AuxiliaryLists) {
        let display_list_descriptors = display_lists.iter().map(|&(display_list_id,
                                                                   ref built_display_list)| {
            (display_list_id, (*built_display_list.descriptor()).clone())
        }).collect();
        let msg = ApiMsg::SetRootStackingContext(stacking_context_id,
                                                 background_color,
                                                 epoch,
                                                 pipeline_id,
                                                 viewport_size,
                                                 stacking_contexts,
                                                 display_list_descriptors,
                                                 *auxiliary_lists.descriptor());
        self.api_sender.send(msg).unwrap();

        let mut payload = vec![];
        payload.write_u32::<LittleEndian>(stacking_context_id.0).unwrap();
        payload.write_u32::<LittleEndian>(epoch.0).unwrap();

        for &(_, ref built_display_list) in &display_lists {
            payload.extend_from_slice(built_display_list.data());
        }
        payload.extend_from_slice(auxiliary_lists.data());

        self.payload_sender.send(&payload[..]).unwrap();
    }

    pub fn scroll(&self, delta: Point2D<f32>, cursor: Point2D<f32>, phase: ScrollEventPhase) {
        let msg = ApiMsg::Scroll(delta, cursor, phase);
        self.api_sender.send(msg).unwrap();
    }

    pub fn tick_scrolling_bounce_animations(&self) {
        let msg = ApiMsg::TickScrollingBounce;
        self.api_sender.send(msg).unwrap();
    }

    pub fn translate_point_to_layer_space(&self, point: &Point2D<f32>)
                                          -> (Point2D<f32>, PipelineId) {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx);
        self.api_sender.send(msg).unwrap();
        rx.recv().unwrap()
    }

    pub fn request_webgl_context(&self, size: &Size2D<i32>, attributes: GLContextAttributes)
                                 -> Result<(WebGLContextId, GLLimits), String> {
        let (tx, rx) = ipc::channel().unwrap();
        let msg = ApiMsg::RequestWebGLContext(*size, attributes, tx);
        self.api_sender.send(msg).unwrap();
        rx.recv().unwrap()
    }

    pub fn send_webgl_command(&self, context_id: WebGLContextId, command: WebGLCommand) {
        let msg = ApiMsg::WebGLCommand(context_id, command);
        self.api_sender.send(msg).unwrap();
    }

    #[inline]
    pub fn next_stacking_context_id(&self) -> StackingContextId {
        let new_id = self.next_unique_id();
        StackingContextId(new_id.0, new_id.1)
    }

    #[inline]
    pub fn next_display_list_id(&self) -> DisplayListId {
        let new_id = self.next_unique_id();
        DisplayListId(new_id.0, new_id.1)
    }

    #[inline]
    fn next_unique_id(&self) -> (u32, u32) {
        let IdNamespace(namespace) = self.id_namespace;
        let ResourceId(id) = self.next_id.get();
        self.next_id.set(ResourceId(id + 1));
        (namespace, id)
    }
}

<|endoftext|>


<commit_before>//! Implements two-state "pinger" task that drives sending pings to the server to check liveness of
//! the connection.

use futures::FutureExt;
use futures::{pin_mut, select, stream::StreamExt};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::timer::delay_for;

pub(crate) struct Pinger {
    snd_rst: mpsc::Sender<()>,
}

#[derive(Debug)]
pub(crate) enum Event {
    SendPing,
    Disconnect,
}

enum PingerState {
    /// Signal a "ping" on timeout. State moves to `ExpectPong`.
    SendPing,
    /// Signal a "disconnect" on timeout.
    ExpectPong,
}

async fn pinger_task(rcv_rst: mpsc::Receiver<()>, mut snd_ev: mpsc::Sender<Event>) {
    let mut rcv_rst_fused = rcv_rst.fuse();
    let mut state = PingerState::SendPing;
    loop {
        // NOTE: The code about does not work:
        // let mut delay = delay_for(Duration::from_secs(30));
        // Instead I need this weird code below. Not sure if this is a bug or not.
        let delay = async {
            delay_for(Duration::from_secs(30)).await;
        }
            .fuse();
        pin_mut!(delay);

        eprintln!("pinger: select");
        select! {
            () = delay => {
                eprintln!("pinger: delay yielded");
                match state {
                    PingerState::SendPing => {
                        state = PingerState::ExpectPong;
                        eprintln!("pinger: SendPing");
                        snd_ev.try_send(Event::SendPing).unwrap();
                    }
                    PingerState::ExpectPong => {
                        eprintln!("pinger: Disconnect");
                        snd_ev.try_send(Event::Disconnect).unwrap();
                        return;
                    }
                }
            }
            cmd = rcv_rst_fused.next() => {
                eprintln!("pinger: rcv_rst yielded");
                match cmd {
                    None => {
                        eprintln!("pinger: Return");
                        return;
                    }
                    Some(()) => {
                        eprintln!("pinger: Reset");
                        state = PingerState::SendPing;
                    }
                }
            }
        }
    }
}

impl Pinger {
    pub(crate) fn new() -> (Pinger, mpsc::Receiver<Event>) {
        let (snd_ev, rcv_ev) = mpsc::channel(1);
        // No need for sending another "reset" when there's already one waiting to be processed
        let (snd_rst, rcv_rst) = mpsc::channel(1);
        tokio::runtime::current_thread::spawn(pinger_task(rcv_rst, snd_ev));
        (Pinger { snd_rst }, rcv_ev)
    }

    pub(crate) fn reset(&mut self) {
        // Ignore errors: no need to send another "reset" when there's already one waiting to be
        // processed
        let _ = self.snd_rst.try_send(());
    }
}
<commit_msg>Bump ping/pong delay to 60 secs<commit_after>//! Implements two-state "pinger" task that drives sending pings to the server to check liveness of
//! the connection.

use futures::FutureExt;
use futures::{pin_mut, select, stream::StreamExt};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::timer::delay_for;

pub(crate) struct Pinger {
    snd_rst: mpsc::Sender<()>,
}

#[derive(Debug)]
pub(crate) enum Event {
    SendPing,
    Disconnect,
}

enum PingerState {
    /// Signal a "ping" on timeout. State moves to `ExpectPong`.
    SendPing,
    /// Signal a "disconnect" on timeout.
    ExpectPong,
}

async fn pinger_task(rcv_rst: mpsc::Receiver<()>, mut snd_ev: mpsc::Sender<Event>) {
    let mut rcv_rst_fused = rcv_rst.fuse();
    let mut state = PingerState::SendPing;
    loop {
        // NOTE: The code about does not work:
        // let mut delay = delay_for(Duration::from_secs(30));
        // Instead I need this weird code below. Not sure if this is a bug or not.
        let delay = async {
            delay_for(Duration::from_secs(60)).await;
        }
            .fuse();
        pin_mut!(delay);

        eprintln!("pinger: select");
        select! {
            () = delay => {
                eprintln!("pinger: delay yielded");
                match state {
                    PingerState::SendPing => {
                        state = PingerState::ExpectPong;
                        eprintln!("pinger: SendPing");
                        snd_ev.try_send(Event::SendPing).unwrap();
                    }
                    PingerState::ExpectPong => {
                        eprintln!("pinger: Disconnect");
                        snd_ev.try_send(Event::Disconnect).unwrap();
                        return;
                    }
                }
            }
            cmd = rcv_rst_fused.next() => {
                eprintln!("pinger: rcv_rst yielded");
                match cmd {
                    None => {
                        eprintln!("pinger: Return");
                        return;
                    }
                    Some(()) => {
                        eprintln!("pinger: Reset");
                        state = PingerState::SendPing;
                    }
                }
            }
        }
    }
}

impl Pinger {
    pub(crate) fn new() -> (Pinger, mpsc::Receiver<Event>) {
        let (snd_ev, rcv_ev) = mpsc::channel(1);
        // No need for sending another "reset" when there's already one waiting to be processed
        let (snd_rst, rcv_rst) = mpsc::channel(1);
        tokio::runtime::current_thread::spawn(pinger_task(rcv_rst, snd_ev));
        (Pinger { snd_rst }, rcv_ev)
    }

    pub(crate) fn reset(&mut self) {
        // Ignore errors: no need to send another "reset" when there's already one waiting to be
        // processed
        let _ = self.snd_rst.try_send(());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;

use bencher::Bencher;
use std::{fs::File, io::BufRead, io::BufReader, io::Read};
use time::Tm;

use libtiny_tui::trie::Trie;
use libtiny_tui::tui::TUI;
use libtiny_tui::MsgTarget;

static DICT_FILE: &str = "/usr/share/dict/american-english";

fn trie_build(b: &mut Bencher) {
    // Total words: 305,089
    // 117,701,680 ns (0.1 seconds)
    // (before reversing the list: 116,795,268 ns (0.1 seconds))

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    b.iter(|| {
        let mut trie = Trie::new();
        // Note that we insert the words in reverse order here. Since the
        // dictionary is already sorted, we end up benchmarking the best case.
        // Since that best case is never really happens in practice, the number
        // is practically useless. Worst case is at least giving an upper bound.
        for word in words.iter().rev() {
            trie.insert(word);
        }
        trie
    });
}

fn hashset_build(b: &mut Bencher) {
    // Total words: 305,089
    // 40,292,006 ns (0.04 seconds)

    use std::collections::HashSet;

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        let mut file = File::open(DICT_FILE).unwrap();
        file.read_to_string(&mut contents).unwrap();
        words.extend(contents.lines());
    }

    b.iter(|| {
        let mut set = HashSet::new();
        for word in words.iter() {
            set.insert(word);
        }
        set
    });
}

fn trie_lookup(b: &mut Bencher) {
    // Total:     305,089 words
    // Returning:     235 words
    // 140,717 ns (0.14 ms)

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    let mut trie = Trie::new();
    for word in words {
        trie.insert(word);
    }

    b.iter(|| trie.drop_pfx(&mut "abs".chars()));
}

fn trie_list_all(b: &mut Bencher) {
    // Total:     305,089 words
    // Returning: 305,089 words
    // 205,946,060 ns (0.2 s)

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    let mut trie = Trie::new();
    for word in words {
        trie.insert(word);
    }

    b.iter(|| trie.drop_pfx(&mut "".chars()));
}

fn tui_resize(b: &mut Bencher) {
    let mut tui = TUI::new_test(80, 50);

    let server = "<server>";
    tui.new_server_tab(server, None);

    let ts: Tm = unsafe { ::std::mem::zeroed() };
    let target = MsgTarget::CurrentTab;

    let f = File::open("test/lipsum.txt").unwrap();
    let f = BufReader::new(f);
    for line in f.lines() {
        let line = line.unwrap();
        tui.add_msg(&line, ts, &target);
    }

    b.iter(|| {
        let mut w = 80;
        let mut h = 50;

        for _ in 0..50 {
            w -= 1;
            h -= 1;
            tui.set_size(w, h);
            tui.draw();
        }

        for _ in 0..50 {
            w += 1;
            h += 1;
            tui.set_size(w, h);
            tui.draw();
        }
    });
}

benchmark_group!(
    benches,
    trie_build,
    hashset_build,
    trie_lookup,
    trie_list_all,
    tui_resize
);
benchmark_main!(benches);
<commit_msg>Remove an unsafe block in TUI benchmarks<commit_after>#[macro_use]
extern crate bencher;

use bencher::Bencher;
use std::{fs::File, io::BufRead, io::BufReader, io::Read};
use time::Tm;

use libtiny_tui::trie::Trie;
use libtiny_tui::tui::TUI;
use libtiny_tui::MsgTarget;

static DICT_FILE: &str = "/usr/share/dict/american-english";

fn trie_build(b: &mut Bencher) {
    // Total words: 305,089
    // 117,701,680 ns (0.1 seconds)
    // (before reversing the list: 116,795,268 ns (0.1 seconds))

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    b.iter(|| {
        let mut trie = Trie::new();
        // Note that we insert the words in reverse order here. Since the
        // dictionary is already sorted, we end up benchmarking the best case.
        // Since that best case is never really happens in practice, the number
        // is practically useless. Worst case is at least giving an upper bound.
        for word in words.iter().rev() {
            trie.insert(word);
        }
        trie
    });
}

fn hashset_build(b: &mut Bencher) {
    // Total words: 305,089
    // 40,292,006 ns (0.04 seconds)

    use std::collections::HashSet;

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        let mut file = File::open(DICT_FILE).unwrap();
        file.read_to_string(&mut contents).unwrap();
        words.extend(contents.lines());
    }

    b.iter(|| {
        let mut set = HashSet::new();
        for word in words.iter() {
            set.insert(word);
        }
        set
    });
}

fn trie_lookup(b: &mut Bencher) {
    // Total:     305,089 words
    // Returning:     235 words
    // 140,717 ns (0.14 ms)

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    let mut trie = Trie::new();
    for word in words {
        trie.insert(word);
    }

    b.iter(|| trie.drop_pfx(&mut "abs".chars()));
}

fn trie_list_all(b: &mut Bencher) {
    // Total:     305,089 words
    // Returning: 305,089 words
    // 205,946,060 ns (0.2 s)

    let mut contents = String::new();
    let mut words: Vec<&str> = vec![];
    {
        match File::open(DICT_FILE) {
            Err(_) => {
                println!("Can't open dictionary file, aborting benchmark.");
                return;
            }
            Ok(mut file) => {
                file.read_to_string(&mut contents).unwrap();
                words.extend(contents.lines());
            }
        }
    }

    let mut trie = Trie::new();
    for word in words {
        trie.insert(word);
    }

    b.iter(|| trie.drop_pfx(&mut "".chars()));
}

fn tui_resize(b: &mut Bencher) {
    let mut tui = TUI::new_test(80, 50);

    let server = "<server>";
    tui.new_server_tab(server, None);

    let ts: Tm = time::empty_tm();
    let target = MsgTarget::CurrentTab;

    let f = File::open("test/lipsum.txt").unwrap();
    let f = BufReader::new(f);
    for line in f.lines() {
        let line = line.unwrap();
        tui.add_msg(&line, ts, &target);
    }

    b.iter(|| {
        let mut w = 80;
        let mut h = 50;

        for _ in 0..50 {
            w -= 1;
            h -= 1;
            tui.set_size(w, h);
            tui.draw();
        }

        for _ in 0..50 {
            w += 1;
            h += 1;
            tui.set_size(w, h);
            tui.draw();
        }
    });
}

benchmark_group!(
    benches,
    trie_build,
    hashset_build,
    trie_lookup,
    trie_list_all,
    tui_resize
);
benchmark_main!(benches);
<|endoftext|>


<commit_before>use sdl2;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::render::Texture as SdlTexture;
use sdl2::mixer;
use OptionLoaned;
use input_private;
use input::Input;
use input_private::input;
use game_object::GameObject;
use component::Message;
use game_object;
use graphics::Texture;
use graphics_private::texture;
use graphics::Sprite;
use graphics_private::sprite_sheet;
use math::PolarCoords;
use math::Vector;
use math::IntVector;
use math_private::int_vector::IntVecConvert;
use audio::Audio;
use audio_private::audio;
use audio_private::playlist;
use math::Transform;
use graphics::Canvas;
use camera::Camera;
use nphysics2d::world::World;
use nphysics2d::math::Translation;
use nalgebra::geometry::UnitComplex;
use std::sync::Arc;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

/// This structure represents a game instance.
///
/// This structure is responsible for managing asset loading,
/// processing input, rendering the game and playing audio.
pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    texture_cache: HashMap<String, Arc<SdlTexture>>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
    pub audio: Audio,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        let input = input::new(sdl_context.mouse());
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: input,
            renderer: renderer,
            texture_cache: HashMap::new(),
            audio: audio::new(audio, mixer),
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new(Vector::new(0.0, 0.0), 0.0) },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                if let Some(ref sprite) = game_obj.sprite {
                    let mut render_transform = game_obj.transform;
                    render_transform.translation.vector.x -= camera_transform.translation.vector.x;
                    render_transform.translation.vector.y -= camera_transform.translation.vector.y;
                    let mut polar = PolarCoords::from(render_transform.translation.vector.clone());
                    polar.rotation -= camera_transform.rotation.angle();
                    render_transform.translation = Translation::from_vector(Vector::from(polar));
                    render_transform.translation.vector.x += (screen_width / 2) as f32;
                    render_transform.translation.vector.y += (screen_height / 2) as f32;
                    render_transform.rotation = UnitComplex::from_angle(render_transform.rotation.angle() - camera_transform.rotation.angle());
                    match *sprite {
                        Sprite::Texture(ref texture) => {
                            let (tex_width, tex_height) = texture::size(texture);
                            let render_rect = Rect::new((render_transform.translation.vector.x as i32) -
                                                        (tex_width as i32 / 2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (tex_height as i32 / 2),
                                                        tex_width,
                                                        tex_height);
                            let result = self.renderer.copy_ex(texture::get_raw(texture),
                                                               None,
                                                               Some(render_rect),
                                                               (game_obj.transform.rotation.angle() *
                                                                180.0 /
                                                                f32::consts::PI) as
                                                               f64,
                                                               None,
                                                               texture.flip_horizontal,
                                                               texture.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                        Sprite::SpriteSheet(ref sprite_sheet) => {
                            let ref current_frame = sprite_sheet.animations[sprite_sheet.current_animation as
                            usize]
                                [sprite_sheet.current_frame as usize];
                            let result = self.renderer
                                .copy_ex(sprite_sheet::get_texture(sprite_sheet),
                                         Some(Rect::from(current_frame.frame_rect)),
                                         Some(Rect::new((render_transform.translation.vector.x as i32) -
                                                        (current_frame.frame_rect.width() as i32 /
                                                         2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (current_frame.frame_rect.height() as i32 /
                                                         2),
                                                        current_frame.frame_rect.width(),
                                                        current_frame.frame_rect.height())),
                                         (game_obj.transform.rotation.angle() * 180.0 /
                                          f32::consts::PI) as
                                         f64,
                                         None,
                                         current_frame.flip_horizontal,
                                         current_frame.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                    }
                }
            }
        }
        {
            let mut canvas = Canvas::new(&mut self.renderer);
            for game_obj in game_objs.values() {
                if let Some(ref game_obj) = *game_obj {
                    for key in game_obj.component_keys() {
                        if let OptionLoaned::Some(component) = game_obj.component(key) {
                            component.render_gui(&mut canvas, game_obj);
                        }
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        // Advance audio if necessary.
        playlist::advance_if_needed(&mut self.audio.playlist);
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects
            .keys()
            .map(|x| *x)
            .collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                            .unwrap()
                            .num_microseconds()
                            .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    pub fn world_mouse_pos(&self) -> Vector {
         let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        self.camera.transform.translation.vector + (self.input.mouse.pos() - IntVector::new(screen_width as i32, screen_height as i32)).to_vec()
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionLoaned<&GameObject> {
        OptionLoaned::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionLoaned<&mut GameObject> {
        OptionLoaned::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        if let Some(sdl_texture) = self.texture_cache.get(texture_name) {
            return Ok(texture::new(sdl_texture.clone()));
        }
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let sdl_texture = Arc::new(sdl_texture);
        self.texture_cache.insert(texture_name.to_string(), sdl_texture.clone());
        Ok(texture::new(sdl_texture))
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<commit_msg>Fix mouse_world_pos<commit_after>use sdl2;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::render::Texture as SdlTexture;
use sdl2::mixer;
use OptionLoaned;
use input_private;
use input::Input;
use input_private::input;
use game_object::GameObject;
use component::Message;
use game_object;
use graphics::Texture;
use graphics_private::texture;
use graphics::Sprite;
use graphics_private::sprite_sheet;
use math::PolarCoords;
use math::Vector;
use math::IntVector;
use math_private::int_vector::IntVecConvert;
use audio::Audio;
use audio_private::audio;
use audio_private::playlist;
use math::Transform;
use graphics::Canvas;
use camera::Camera;
use nphysics2d::world::World;
use nphysics2d::math::Translation;
use nalgebra::geometry::UnitComplex;
use std::sync::Arc;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

/// This structure represents a game instance.
///
/// This structure is responsible for managing asset loading,
/// processing input, rendering the game and playing audio.
pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    texture_cache: HashMap<String, Arc<SdlTexture>>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
    pub audio: Audio,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        let input = input::new(sdl_context.mouse());
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: input,
            renderer: renderer,
            texture_cache: HashMap::new(),
            audio: audio::new(audio, mixer),
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new(Vector::new(0.0, 0.0), 0.0) },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();
        let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                if let Some(ref sprite) = game_obj.sprite {
                    let mut render_transform = game_obj.transform;
                    render_transform.translation.vector.x -= camera_transform.translation.vector.x;
                    render_transform.translation.vector.y -= camera_transform.translation.vector.y;
                    let mut polar = PolarCoords::from(render_transform.translation.vector.clone());
                    polar.rotation -= camera_transform.rotation.angle();
                    render_transform.translation = Translation::from_vector(Vector::from(polar));
                    render_transform.translation.vector.x += (screen_width / 2) as f32;
                    render_transform.translation.vector.y += (screen_height / 2) as f32;
                    render_transform.rotation = UnitComplex::from_angle(render_transform.rotation.angle() - camera_transform.rotation.angle());
                    match *sprite {
                        Sprite::Texture(ref texture) => {
                            let (tex_width, tex_height) = texture::size(texture);
                            let render_rect = Rect::new((render_transform.translation.vector.x as i32) -
                                                        (tex_width as i32 / 2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (tex_height as i32 / 2),
                                                        tex_width,
                                                        tex_height);
                            let result = self.renderer.copy_ex(texture::get_raw(texture),
                                                               None,
                                                               Some(render_rect),
                                                               (game_obj.transform.rotation.angle() *
                                                                180.0 /
                                                                f32::consts::PI) as
                                                               f64,
                                                               None,
                                                               texture.flip_horizontal,
                                                               texture.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                        Sprite::SpriteSheet(ref sprite_sheet) => {
                            let ref current_frame = sprite_sheet.animations[sprite_sheet.current_animation as
                            usize]
                                [sprite_sheet.current_frame as usize];
                            let result = self.renderer
                                .copy_ex(sprite_sheet::get_texture(sprite_sheet),
                                         Some(Rect::from(current_frame.frame_rect)),
                                         Some(Rect::new((render_transform.translation.vector.x as i32) -
                                                        (current_frame.frame_rect.width() as i32 /
                                                         2),
                                                        (render_transform.translation.vector.y as i32) -
                                                        (current_frame.frame_rect.height() as i32 /
                                                         2),
                                                        current_frame.frame_rect.width(),
                                                        current_frame.frame_rect.height())),
                                         (game_obj.transform.rotation.angle() * 180.0 /
                                          f32::consts::PI) as
                                         f64,
                                         None,
                                         current_frame.flip_horizontal,
                                         current_frame.flip_vertical);
                            if let Err(err) = result {
                                println!("Unable to draw texture, Error: {:?}", err);
                            }
                        }
                    }
                }
            }
        }
        {
            let mut canvas = Canvas::new(&mut self.renderer);
            for game_obj in game_objs.values() {
                if let Some(ref game_obj) = *game_obj {
                    for key in game_obj.component_keys() {
                        if let OptionLoaned::Some(component) = game_obj.component(key) {
                            component.render_gui(&mut canvas, game_obj);
                        }
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        // Advance audio if necessary.
        playlist::advance_if_needed(&mut self.audio.playlist);
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects
            .keys()
            .map(|x| *x)
            .collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                            .unwrap()
                            .num_microseconds()
                            .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    pub fn world_mouse_pos(&self) -> Vector {
         let (screen_width, screen_height) = self.renderer
            .window()
            .unwrap()
            .size();
        self.camera.transform.translation.vector + (self.input.mouse.pos() - IntVector::new((screen_width / 2) as i32, (screen_height / 2) as i32)).to_vec()
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionLoaned<&GameObject> {
        OptionLoaned::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionLoaned<&mut GameObject> {
        OptionLoaned::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        if let Some(sdl_texture) = self.texture_cache.get(texture_name) {
            return Ok(texture::new(sdl_texture.clone()));
        }
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let sdl_texture = Arc::new(sdl_texture);
        self.texture_cache.insert(texture_name.to_string(), sdl_texture.clone());
        Ok(texture::new(sdl_texture))
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<|endoftext|>


<commit_before>use libc::*;
use std::fs::read_link;
use std::path::PathBuf;
use std::ptr;

// http://stackoverflow.com/q/799679
// http://stackoverflow.com/a/1024937

#[cfg(target_os = "netbsd")]
pub fn get_executable_path() -> Option<PathBuf> {
    read_link("/proc/curproc/exe").ok()
}

#[cfg(target_os = "dragonfly")]
pub fn get_executable_path() -> Option<PathBuf> {
    read_link("/proc/curproc/file").ok()
}

#[cfg(target_os = "freebsd")]
pub fn get_executable_path() -> Option<PathBuf> {
    let mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
    let mut buf: Vec<u8> = Vec::with_capacity(1024);
    let mut cb = 1024 as size_t;
    let result = unsafe {
        sysctl(
            mib.as_ptr(),
            4,
            buf.as_mut_ptr() as *mut c_void,
            &mut cb as *mut size_t,
            ptr::null(),
            0,
        )
    };

    // FreeBSD without procfs
    if result == 0 {
        // Convert the string allocated on the stack to a Rust string.
        let len = unsafe { strlen(buf.as_ptr() as *const i8) };
        unsafe { buf.set_len(len) };
        match String::from_utf8(buf).ok() {
            Some(path) => {
                let mut pb = PathBuf::new();
                pb.push(path);
                Some(pb)
            }
            None => None,
        }
    } else {
        // FreeBSD with procfs
        read_link("/proc/curproc/file").ok()
    }
}
<commit_msg>Fix build on FreeBSD on ARM or POWER<commit_after>use libc::*;
use std::fs::read_link;
use std::path::PathBuf;
use std::ptr;

// http://stackoverflow.com/q/799679
// http://stackoverflow.com/a/1024937

#[cfg(target_os = "netbsd")]
pub fn get_executable_path() -> Option<PathBuf> {
    read_link("/proc/curproc/exe").ok()
}

#[cfg(target_os = "dragonfly")]
pub fn get_executable_path() -> Option<PathBuf> {
    read_link("/proc/curproc/file").ok()
}

#[cfg(target_os = "freebsd")]
pub fn get_executable_path() -> Option<PathBuf> {
    let mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
    let mut buf: Vec<u8> = Vec::with_capacity(1024);
    let mut cb = 1024 as size_t;
    let result = unsafe {
        sysctl(
            mib.as_ptr(),
            4,
            buf.as_mut_ptr() as *mut c_void,
            &mut cb as *mut size_t,
            ptr::null(),
            0,
        )
    };

    // FreeBSD without procfs
    if result == 0 {
        // Convert the string allocated on the stack to a Rust string.
        let len = unsafe { strlen(buf.as_ptr() as *const libc::c_char) };
        unsafe { buf.set_len(len) };
        match String::from_utf8(buf).ok() {
            Some(path) => {
                let mut pb = PathBuf::new();
                pb.push(path);
                Some(pb)
            }
            None => None,
        }
    } else {
        // FreeBSD with procfs
        read_link("/proc/curproc/file").ok()
    }
}
<|endoftext|>


<commit_before>use aes::*;
use byte_conversion::*;
use byte_manipulation::*;
use ciphertext::*;
use key::*;

pub struct CipherBlock {
	initialisation_vector: Vec<u8>,
	input: PaddedBytes,
	key: RepeatingKey,
}

impl CipherBlock {
	pub fn to_ciphertext(&mut self) -> Vec<u8> {
		let xored = xor_byte_streams(&self.initialisation_vector, self.input.vec());
		let key = self.key.of_length(16);
		let cipher = encrypt_aes_128_ecb_no_padding(&xored[..], &key);

		cipher.unwrap()
	}
}

//-----------------------------------------------------------------------------

#[cfg(test)]
#[allow(non_snake_case)]
mod test {
	use super::*;

	use byte_conversion::*;
	use ciphertext::*;
	use key::*;

	#[test]
	fn RepeatingKey_sanity() {
		let mut cipher_block = CipherBlock {
			input: PaddedBytes::from_text("Some text", 16).unwrap(),
			initialisation_vector: RepeatingKey::new(&"\x00").of_length(16),
			key: RepeatingKey::new(&"YELLOW SUBMARINE"),
		};

		assert_eq!(16, cipher_block.to_ciphertext().len());
	}
}<commit_msg>CBC decryption<commit_after>use aes::*;
use byte_conversion::*;
use byte_manipulation::*;
use ciphertext::*;
use key::*;

pub struct CipherBlock {
	initialisation_vector: Vec<u8>,
	input: PaddedBytes,
	key: RepeatingKey,
}

impl CipherBlock {
	pub fn to_ciphertext(&mut self) -> Vec<u8> {
		let xored = xor_byte_streams(&self.initialisation_vector, self.input.vec());
		let key = self.key.of_length(16);
		let cipher = encrypt_aes_128_ecb_no_padding(&xored[..], &key);

		cipher.unwrap()
	}

	pub fn to_plaintext(&mut self) -> Vec<u8> {
		let key = self.key.of_length(16);
		let decipher = decrypt_aes_128_ecb_no_padding(self.input.bytes(), &key).unwrap();
		let xored = xor_byte_streams(&self.initialisation_vector, &decipher);

		xored
	}
}

//-----------------------------------------------------------------------------

#[cfg(test)]
#[allow(non_snake_case)]
mod test {
	use super::*;

	use byte_conversion::*;
	use ciphertext::*;
	use key::*;

	#[test]
	fn RepeatingKey_sanity() {
		let mut cipher_block = CipherBlock {
			input: PaddedBytes::from_text("Some text", 16).unwrap(),
			initialisation_vector: RepeatingKey::new(&"\x00").of_length(16),
			key: RepeatingKey::new(&"YELLOW SUBMARINE"),
		};

		assert_eq!(16, cipher_block.to_ciphertext().len());
	}

	#[test]
	fn RepeatingKey_encrypt_decrypt_equal() {
		fn plaintext() -> PaddedBytes { PaddedBytes::from_text("Some text", 16).unwrap() };
		fn IV() -> Vec<u8> { RepeatingKey::new(&"\x00").of_length(16) };
		fn key() -> RepeatingKey { RepeatingKey::new(&"YELLOW SUBMARINE") };

		let mut cipher_block = CipherBlock {
			input: plaintext(),
			initialisation_vector: IV(),
			key: key(),
		};

		let ciphertext = cipher_block.to_ciphertext();

		let mut decrypt_cipher = CipherBlock {
			input: PaddedBytes::from_bytes(&ciphertext[..], 16).unwrap(),
			initialisation_vector: IV(),
			key: key(),
		};

		assert_eq!(plaintext().vec(), &decrypt_cipher.to_plaintext());
	}
}<|endoftext|>


<commit_before>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[derive(Default)]
pub struct ClearLocalInterruptsGuard<T> {
    guarded: T,
    count: AtomicUsize,
}

impl<T> ClearLocalInterruptsGuard<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterruptsGuard {
            guarded: guarded,
            count: ATOMIC_USIZE_INIT,
        }
    }
}

impl<T> ops::Deref for ClearLocalInterruptsGuard<T> {
    type Target = T;
    fn deref(&self) -> &T {
        cli();
        if self.count.fetch_add(1, Ordering::AcqRel) == 0 {
            CLI_COUNT.get().fetch_add(1, Ordering::AcqRel);
        }
        &self.guarded
    }
}

impl<T> ops::DerefMut for ClearLocalInterruptsGuard<T> {
    fn deref_mut(&mut self) -> &mut T {
        cli();
        if self.count.fetch_add(1, Ordering::AcqRel) == 0 {
            CLI_COUNT.get().fetch_add(1, Ordering::AcqRel);
        }
        &mut self.guarded
    }
}

impl<T> Drop for ClearLocalInterruptsGuard<T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterruptsGuard;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterruptsGuard<Guardee> = ClearLocalInterruptsGuard::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterruptsGuard<Guardee> = ClearLocalInterruptsGuard::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            (*g).data += 1;
            assert!(!are_interrupts_enabled());
            assert_eq!((*g).data, 1);
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterruptsGuard<Guardee> = ClearLocalInterruptsGuard::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            (*g).do_work();
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            (*STATIC_GUARDEE).do_work();
            assert!(!are_interrupts_enabled());
            assert_eq!((*STATIC_GUARDEE).data, 0);
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

}
<commit_msg>Improved and better tested cli<commit_after>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    info!("Clearing interrupts!");
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() { }

#[cfg(not(test))]
pub fn sti() {
    info!("Restoring interrupts!");
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() { }

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts {
            guarded: guarded,
        }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        info!("new mut!");
        ClearLocalInterruptsGuardMut { guarded: &mut self.guarded, acquired: ATOMIC_BOOL_INIT }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        info!("new!");
        ClearLocalInterruptsGuard { guarded: &self.guarded, acquired: ATOMIC_BOOL_INIT }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        info!("Drop! {}", CLI_COUNT.get().load(Ordering::Relaxed));
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        info!("Drop! {}", CLI_COUNT.get().load(Ordering::Relaxed));
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = &g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<|endoftext|>


<commit_before>use instruction::{ Instruction, Register, Address, Value };
use rand;
use rand::Rng;

const INSTRUCTION_SIZE: u16 = 2;

pub struct Cpu {
    memory: [u8; 4096],
    registers: [u8; 16],
    index: u16,
    pc: u16,
    stack: [u16; 16],
    sp: u16,
    del_timer: u8,
    sound_timer: u8,
    pub draw_flag: bool,
    pub faulted: bool,
}

impl Cpu {
    pub fn new(game_data: Vec<u8>) -> Cpu {
        let mut memory = [0; 4096];
        for (i, byte) in game_data.iter().enumerate() {
            memory[0x200 + i] = byte.clone();
        }

        Cpu {
            memory: memory,
            registers: [0; 16],
            index: 0,
            pc: 0x200,
            stack: [0; 16],
            sp: 0,
            draw_flag: false,
            faulted: false,
        }
    }

    pub fn cycle(&mut self) {
        if self.faulted {
            return
        }

        let raw_instruction = self.read_next_instruction();
        let instruction = Instruction::parse(raw_instruction);

        println!("[PC:0x{:X}] [RAW:0x{:X}] {}", self.pc, raw_instruction, instruction);

        if instruction == Instruction::InvalidOperation {
            self.faulted = true;
        } else {
            self.execute_instruction(instruction);
            self.print_registers();
            self.handle_timers();
        }
    }

    fn read_next_instruction(&self) -> (u16) {
        let upper = self.memory[self.pc as usize] as u16;
        let lower = self.memory[(self.pc + 1) as usize] as u16;
        upper << 8 | lower
    }

    fn execute_instruction(&mut self, instruction: Instruction) {
        match instruction {
            Instruction::Load(r, v) => self.load_value(r, v),
            Instruction::SetIndexRegister(a) => self.set_index(a),
            Instruction::Random(r, v) => self.rand(r, v),
            Instruction::Jump(a) => self.jump(a),
            Instruction::SkipIfEqual(r, v) => self.skip_equal(r, v),
            Instruction::Draw(r1, r2, v) => self.skip(),
            Instruction::Add(r, v) => self.add(r, v),
            Instruction::Assign(r1, r2) => self.assign(r1, r2),
            Instruction::InvalidOperation => {},
        };
    }

    fn handle_timers(&mut self) {
        if self.del_timer > 0 {
            self.del_timer -= 1;
        }

        if self.sound_timer > 0 {
            // BEEP!
            self.sound_timer -= 1;
        }
    }

    fn read_register(&self, register: Register) -> Value {
        self.registers[register as usize]
    }

    fn set_register(&mut self, register: Register, value: Value) {
        self.registers[register as usize] = value;
    }

    fn skip(&mut self) {
        self.pc += 2;
    }

    fn load_value(&mut self, register: Register, value: Value) {
        self.set_register(register, value);
        self.pc += INSTRUCTION_SIZE;
    }

    fn add(&mut self, register: Register, value: Value) {
        let current_value = self.read_register(register);
        self.set_register(register, current_value + value);
        self.pc += INSTRUCTION_SIZE;
    }

    fn set_index(&mut self, addr: Address) {
        self.index = addr;
        self.pc += INSTRUCTION_SIZE;
    }

    fn jump(&mut self, addr: Address) {
        self.pc = addr;
    }

    fn skip_equal(&mut self, register: Register, value: Value) {
        let reg_val = self.read_register(register);
        let pc_skip = if reg_val == value {
            INSTRUCTION_SIZE * 2
        } else {
            INSTRUCTION_SIZE
        };
        self.pc += pc_skip;
    }

    fn assign(&mut self, register1: Register, register2: Register) {
        let reg2_val = self.read_register(register2);
        self.set_register(register1, reg2_val);
        self.pc += 2;
    }

    fn rand(&mut self, register: Register, value: Value) {
        let rand_val = rand::thread_rng().gen::<u8>();
        self.set_register(register, value & rand_val);
        self.pc += 2;
    }

    fn print_registers(&self) {
        let reg = self.registers;
        println!("V0:{} V1:{} V2:{} V3:{} V4:{} V5:{} V6:{} V7:{}",
            reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]);
        println!("V8:{} V9:{} VA:{} VB:{} VC:{} VD:{} VE:{} VF:{}",
            reg[8], reg[9], reg[10], reg[11], reg[12], reg[13], reg[14], reg[15]);
    }
}
<commit_msg>Added timer defaults to new()<commit_after>use instruction::{ Instruction, Register, Address, Value };
use rand;
use rand::Rng;

const INSTRUCTION_SIZE: u16 = 2;

pub struct Cpu {
    memory: [u8; 4096],
    registers: [u8; 16],
    index: u16,
    pc: u16,
    stack: [u16; 16],
    sp: u16,
    del_timer: u8,
    sound_timer: u8,
    pub draw_flag: bool,
    pub faulted: bool,
}

impl Cpu {
    pub fn new(game_data: Vec<u8>) -> Cpu {
        let mut memory = [0; 4096];
        for (i, byte) in game_data.iter().enumerate() {
            memory[0x200 + i] = byte.clone();
        }

        Cpu {
            memory: memory,
            registers: [0; 16],
            index: 0,
            pc: 0x200,
            stack: [0; 16],
            sp: 0,
            del_timer: 0,
            sound_timer: 0,
            draw_flag: false,
            faulted: false,
        }
    }

    pub fn cycle(&mut self) {
        if self.faulted {
            return
        }

        let raw_instruction = self.read_next_instruction();
        let instruction = Instruction::parse(raw_instruction);

        println!("[PC:0x{:X}] [RAW:0x{:X}] {}", self.pc, raw_instruction, instruction);

        if instruction == Instruction::InvalidOperation {
            self.faulted = true;
        } else {
            self.execute_instruction(instruction);
            self.print_registers();
            self.handle_timers();
        }
    }

    fn read_next_instruction(&self) -> (u16) {
        let upper = self.memory[self.pc as usize] as u16;
        let lower = self.memory[(self.pc + 1) as usize] as u16;
        upper << 8 | lower
    }

    fn execute_instruction(&mut self, instruction: Instruction) {
        match instruction {
            Instruction::Load(r, v) => self.load_value(r, v),
            Instruction::SetIndexRegister(a) => self.set_index(a),
            Instruction::Random(r, v) => self.rand(r, v),
            Instruction::Jump(a) => self.jump(a),
            Instruction::SkipIfEqual(r, v) => self.skip_equal(r, v),
            Instruction::Draw(r1, r2, v) => self.skip(),
            Instruction::Add(r, v) => self.add(r, v),
            Instruction::Assign(r1, r2) => self.assign(r1, r2),
            Instruction::InvalidOperation => {},
        };
    }

    fn handle_timers(&mut self) {
        if self.del_timer > 0 {
            self.del_timer -= 1;
        }

        if self.sound_timer > 0 {
            // BEEP!
            self.sound_timer -= 1;
        }
    }

    fn read_register(&self, register: Register) -> Value {
        self.registers[register as usize]
    }

    fn set_register(&mut self, register: Register, value: Value) {
        self.registers[register as usize] = value;
    }

    fn skip(&mut self) {
        self.pc += 2;
    }

    fn load_value(&mut self, register: Register, value: Value) {
        self.set_register(register, value);
        self.pc += INSTRUCTION_SIZE;
    }

    fn add(&mut self, register: Register, value: Value) {
        let current_value = self.read_register(register);
        self.set_register(register, current_value + value);
        self.pc += INSTRUCTION_SIZE;
    }

    fn set_index(&mut self, addr: Address) {
        self.index = addr;
        self.pc += INSTRUCTION_SIZE;
    }

    fn jump(&mut self, addr: Address) {
        self.pc = addr;
    }

    fn skip_equal(&mut self, register: Register, value: Value) {
        let reg_val = self.read_register(register);
        let pc_skip = if reg_val == value {
            INSTRUCTION_SIZE * 2
        } else {
            INSTRUCTION_SIZE
        };
        self.pc += pc_skip;
    }

    fn assign(&mut self, register1: Register, register2: Register) {
        let reg2_val = self.read_register(register2);
        self.set_register(register1, reg2_val);
        self.pc += 2;
    }

    fn rand(&mut self, register: Register, value: Value) {
        let rand_val = rand::thread_rng().gen::<u8>();
        self.set_register(register, value & rand_val);
        self.pc += 2;
    }

    fn print_registers(&self) {
        let reg = self.registers;
        println!("V0:{} V1:{} V2:{} V3:{} V4:{} V5:{} V6:{} V7:{}",
            reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]);
        println!("V8:{} V9:{} VA:{} VB:{} VC:{} VD:{} VE:{} VF:{}",
            reg[8], reg[9], reg[10], reg[11], reg[12], reg[13], reg[14], reg[15]);
    }
}
<|endoftext|>


<commit_before>use chrono::DateTime;
use chrono::prelude::Utc;
use rand::distributions::{IndependentSample, Range};
use rand;
use uuid::Uuid;

#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum DieType {
    D4,
    D6,
    D8,
    D10,
    D12,
    D20,
    D100,
    Fate,
    Other,
}

/// Determine the minimum number to roll based on the die type
fn get_die_min(die: &DieType) -> i16 {
    match die {
        &DieType::D4 => 1,
        &DieType::D6 => 1,
        &DieType::D8 => 1,
        &DieType::D10 => 1,
        &DieType::D12 => 1,
        &DieType::D20 => 1,
        &DieType::D100 => 1,
        &DieType::Fate => -1,
        &DieType::Other => 0,
    }
}

/// Determine the minimum number to roll based on the die type
fn get_die_max(die: &DieType) -> i16 {
    match die {
        &DieType::D4 => 4,
        &DieType::D6 => 6,
        &DieType::D8 => 8,
        &DieType::D10 => 10,
        &DieType::D12 => 12,
        &DieType::D20 => 20,
        &DieType::D100 => 100,
        &DieType::Fate => 1,
        &DieType::Other => 0,
    }
}

/// Determine the number of sides based on the die type
fn get_die_sides(die: &DieType) -> u8 {
    match die {
        &DieType::D4 => 4,
        &DieType::D6 => 6,
        &DieType::D8 => 8,
        &DieType::D10 => 10,
        &DieType::D12 => 12,
        &DieType::D20 => 20,
        &DieType::D100 => 100,
        &DieType::Fate => 3,
        &DieType::Other => 0,
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Die {
    /// Unique identifier of the die
    pub _id: String,

    /// If the die was re-rolled, it will have a child
    pub child: Option<String>,

    /// The type of die (e.g. d20, d100)
    pub die: DieType,

    /// If the die is dropped in the final roll
    pub is_dropped: bool,

    /// If the die is dropped in the final roll
    pub is_rerolled: bool,

    /// Maximum number to roll
    pub max: i16,

    /// Minimum number to roll
    pub min: i16,

    /// The number of faces the die has
    pub sides: u8,

    /// Timestamp of the roll
    pub timestamp: DateTime<Utc>,

    /// The determined value of the dice roll
    pub value: i16,
}

impl Die {
    pub fn new (die: DieType) -> Die {
        Die {
            _id: Uuid::new_v4().to_string(),
            child: None,
            die,
            is_dropped: false,
            is_rerolled: false,
            max: get_die_max(&die),
            min: get_die_min(&die),
            sides: get_die_sides(&die),
            timestamp: Utc::now(),
            value: 0,
        }
    }

    /// Drop the die from the final roll
    pub fn drop(&mut self) {
        self.is_dropped = true
    }

    pub fn rerolled (&mut self, die: &Die) {
        self.is_rerolled = true;
        let id = &die._id;
        self.child = Some(id.to_owned());
    }

    /// Roll the die, generating a random number and calculating any modifiers
    pub fn roll(&mut self) -> &Die {
        // generate a random number
        let between = Range::new(self.min, self.max + 1);
        let mut rng = rand::thread_rng();
        let roll = between.ind_sample(&mut rng);
        self.value = roll;
        self
    }

    pub fn set_sides(&mut self, sides: u8) {
        self.sides = sides
    }

    pub fn set_min(&mut self, min: i16) {
        self.min = min
    }

    pub fn set_max(&mut self, max: i16) {
        self.max = max
    }

}
<commit_msg>add is_successful property to die roll<commit_after>use chrono::DateTime;
use chrono::prelude::Utc;
use rand::distributions::{IndependentSample, Range};
use rand;
use uuid::Uuid;

#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum DieType {
    D4,
    D6,
    D8,
    D10,
    D12,
    D20,
    D100,
    Fate,
    Other,
}

/// Determine the minimum number to roll based on the die type
fn get_die_min(die: &DieType) -> i16 {
    match die {
        &DieType::D4 => 1,
        &DieType::D6 => 1,
        &DieType::D8 => 1,
        &DieType::D10 => 1,
        &DieType::D12 => 1,
        &DieType::D20 => 1,
        &DieType::D100 => 1,
        &DieType::Fate => -1,
        &DieType::Other => 0,
    }
}

/// Determine the minimum number to roll based on the die type
fn get_die_max(die: &DieType) -> i16 {
    match die {
        &DieType::D4 => 4,
        &DieType::D6 => 6,
        &DieType::D8 => 8,
        &DieType::D10 => 10,
        &DieType::D12 => 12,
        &DieType::D20 => 20,
        &DieType::D100 => 100,
        &DieType::Fate => 1,
        &DieType::Other => 0,
    }
}

/// Determine the number of sides based on the die type
fn get_die_sides(die: &DieType) -> u8 {
    match die {
        &DieType::D4 => 4,
        &DieType::D6 => 6,
        &DieType::D8 => 8,
        &DieType::D10 => 10,
        &DieType::D12 => 12,
        &DieType::D20 => 20,
        &DieType::D100 => 100,
        &DieType::Fate => 3,
        &DieType::Other => 0,
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Die {
    /// Unique identifier of the die
    pub _id: String,

    /// If the die was re-rolled, it will have a child
    pub child: Option<String>,

    /// The type of die (e.g. d20, d100)
    pub die: DieType,

    /// If the die is dropped in the final roll
    pub is_dropped: bool,

    /// If the die is dropped in the final roll
    pub is_rerolled: bool,

    /// If the die is successful when we have a comparison
    pub is_successful: bool,

    /// Maximum number to roll
    pub max: i16,

    /// Minimum number to roll
    pub min: i16,

    /// The number of faces the die has
    pub sides: u8,

    /// Timestamp of the roll
    pub timestamp: DateTime<Utc>,

    /// The determined value of the dice roll
    pub value: i16,
}

impl Die {
    pub fn new (die: DieType) -> Die {
        Die {
            _id: Uuid::new_v4().to_string(),
            child: None,
            die,
            is_dropped: false,
            is_rerolled: false,
            is_successful: false,
            max: get_die_max(&die),
            min: get_die_min(&die),
            sides: get_die_sides(&die),
            timestamp: Utc::now(),
            value: 0,
        }
    }

    /// Drop the die from the final roll
    pub fn drop(&mut self) {
        self.is_dropped = true
    }

    pub fn rerolled (&mut self, die: &Die) {
        self.is_rerolled = true;
        let id = &die._id;
        self.child = Some(id.to_owned());
    }

    /// Roll the die, generating a random number and calculating any modifiers
    pub fn roll(&mut self) -> &Die {
        // generate a random number
        let between = Range::new(self.min, self.max + 1);
        let mut rng = rand::thread_rng();
        let roll = between.ind_sample(&mut rng);
        self.value = roll;
        self.is_successful = true;
        self
    }

    pub fn set_sides(&mut self, sides: u8) {
        self.sides = sides
    }

    pub fn set_min(&mut self, min: i16) {
        self.min = min
    }

    pub fn set_max(&mut self, max: i16) {
        self.max = max
    }

}
<|endoftext|>