<commit_before>use std::thread;
use std::sync::Arc;

use glutin::{
    GlProfile,
    GlRequest,
    ContextBuilder,
    WindowedContext,
    PossiblyCurrent,
    dpi::LogicalSize,
    window::{WindowBuilder, Fullscreen},
    event::{
        Event as GlutinEvent,
        StartCause,
        WindowEvent,
        DeviceEvent,
        KeyboardInput,
        VirtualKeyCode,
        ElementState,
    },
    event_loop::{ControlFlow, EventLoop, EventLoopProxy},
};
use tokio::{
    sync::Mutex,
    runtime::{Runtime, Handle},
};

use crate::ipc_protocol::ServerConnection;

use super::{
    app::App,
    renderer::{
        Renderer,
        display_list::DisplayList,
    },
};

/// A custom event used to perform actions within the glutin event loop on the main thread
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum MainThreadAction {
    /// Redraw the window
    Redraw,
    /// Update the window title
    SetTitle(String),
    /// Update the window size (in logical coordinates)
    SetSize(LogicalSize<u32>),
    /// Change the maximized state of the window
    SetIsMaximized(bool),
    /// Change the fullscreen state of the window
    SetIsFullscreen(bool),
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
pub fn main() {
    assert_main_thread();

    // The runtime for driving async code
    let runtime = Runtime::new()
        .expect("unable to spawn tokio runtime to run turtle server process");

    // The state of the drawing and the state/drawings associated with each turtle
    let app = Arc::new(App::default());
    // All of the drawing primitives in the order in which they wil be drawn
    //
    // This is managed separately from the rest of the app state because the display list is shared
    // among pretty much everything and so critical sections containing the display list need to be
    // as short as possible.
    let display_list = Arc::new(Mutex::new(DisplayList::default()));

    let event_loop = EventLoop::with_user_event();

    // Create the proxy that will be given to the thread managing IPC
    let event_loop_proxy = event_loop.create_proxy();

    let window_builder = {
        let drawing = runtime.handle().block_on(app.drawing_mut());
        WindowBuilder::new()
            .with_title(&drawing.title)
            .with_inner_size(LogicalSize {width: drawing.width, height: drawing.height})
    };

    // Create an OpenGL 3.x context for Pathfinder to use
    let gl_context = ContextBuilder::new()
        .with_gl(GlRequest::Latest)
        .with_gl_profile(GlProfile::Core)
        .with_vsync(true)
        .with_double_buffer(Some(true))
        .build_windowed(window_builder, &event_loop)
        .expect("bug: either could not create window or could not build OpenGL context");

    // Load OpenGL, and make the context current
    let gl_context = unsafe { gl_context.make_current().unwrap() };
    gl::load_with(|name| gl_context.get_proc_address(name) as *const _);

    // Need to draw using the physical size in pixels, not the logical size
    let draw_size = gl_context.window().inner_size();
    let mut renderer = Renderer::new(draw_size, gl_context.window().scale_factor());

    event_loop.run(move |event, _, control_flow| match event {
        GlutinEvent::NewEvents(StartCause::Init) => {
            // Spawn the actual server thread(s) that will handle incoming IPC messages and
            // asynchronous update the shared state
            // Note that putting this code here instead of before the event loop causes the turtle
            // to wait for the window to open before `::new()` returns.
            let handle = runtime.handle().clone();
            spawn_async_server(handle, app.clone(), display_list.clone(), event_loop_proxy.clone());
        },

        // Quit if the window is closed or if Esc is pressed and then released
        GlutinEvent::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::Destroyed,
            ..
        } | GlutinEvent::DeviceEvent {
            event: DeviceEvent::Key(KeyboardInput {
                state: ElementState::Released,
                virtual_keycode: Some(VirtualKeyCode::Escape),
                ..
            }),
            ..
        } => {
            *control_flow = ControlFlow::Exit;
        },

        GlutinEvent::WindowEvent {
            event: WindowEvent::ScaleFactorChanged {scale_factor, ..},
            ..
        } => {
            renderer.set_scale_factor(scale_factor);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::WindowEvent {window_id, event} => {
            //TODO: Check if event modifies state and then redraw if necessary
        },
        GlutinEvent::DeviceEvent {device_id, event} => {
            //TODO: Check if event modifies state and then redraw if necessary
        },

        GlutinEvent::UserEvent(MainThreadAction::Redraw) => {
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetTitle(title)) => {
            gl_context.window().set_title(&title);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetSize(size)) => {
            gl_context.window().set_inner_size(size);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsMaximized(is_maximized)) => {
            gl_context.window().set_maximized(is_maximized);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsFullscreen(is_fullscreen)) => {
            gl_context.window().set_fullscreen(if is_fullscreen {
                Some(Fullscreen::Borderless(gl_context.window().current_monitor()))
            } else { None });

            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::RedrawRequested(_) => {
            let handle = runtime.handle();
            handle.block_on(redraw(&app, &display_list, &gl_context, &mut renderer));
            *control_flow = ControlFlow::Wait;
        },

        _ => {},
    });
}

async fn redraw(
    app: &App,
    display_list: &Mutex<DisplayList>,
    gl_context: &WindowedContext<PossiblyCurrent>,
    renderer: &mut Renderer,
) {
    let drawing = {
        // Hold the drawing lock for as little time as possible
        let drawing = app.drawing_mut().await;
        drawing.clone()
    };

    // Locking the turtles before the display list to be consistent with all of the request
    // handlers. Inconsistent lock ordering can cause deadlock.
    let mut turtles = Vec::new();
    for id in app.turtle_ids().await {
        turtles.push(app.turtle(id).await);
    }
    // Very important to have all the data locked before rendering. Do not want renderer to have
    // to figure out how to lock.
    let mut locked_turtles = Vec::with_capacity(turtles.len());
    for turtle in &turtles {
        locked_turtles.push(turtle.lock().await);
    }
    // Renderer only needs (read-only) access to TurtleState
    // Doing this also decouples renderer code from runtime by not having to
    // know about the `MutexGuard` type in tokio
    let turtle_states = locked_turtles.iter().map(|t| &t.state);

    let display_list = display_list.lock().await;

    let draw_size = gl_context.window().inner_size();
    renderer.render(draw_size, &display_list, &drawing, turtle_states);
    gl_context.swap_buffers().expect("unable to swap the buffer (for double buffering)");
}

fn assert_main_thread() {
    // This check isn't foolproof. Someone can always create a thread named "main".
    if thread::current().name().unwrap_or("") != "main" {
        // In order to maintain compatibility with MacOS, we need to make sure that windows are
        // only created on the main thread. We do this check on all platforms so that no one
        // can accidentally make a change that creates the window off of the main thread.
        unreachable!("bug: windows can only be created on the main thread");
    }
}

fn spawn_async_server(
    handle: Handle,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: EventLoopProxy<MainThreadAction>,
) {
    // Spawn root task
    handle.spawn(async {
        let conn = ServerConnection::connect_stdin().await
            .expect("unable to establish turtle server connection");
        super::serve(conn, app, display_list, event_loop).await;
    });
}
<commit_msg>Better explanation of what causes ::new() methods to now wait until the window is open<commit_after>use std::thread;
use std::sync::Arc;

use glutin::{
    GlProfile,
    GlRequest,
    ContextBuilder,
    WindowedContext,
    PossiblyCurrent,
    dpi::LogicalSize,
    window::{WindowBuilder, Fullscreen},
    event::{
        Event as GlutinEvent,
        StartCause,
        WindowEvent,
        DeviceEvent,
        KeyboardInput,
        VirtualKeyCode,
        ElementState,
    },
    event_loop::{ControlFlow, EventLoop, EventLoopProxy},
};
use tokio::{
    sync::Mutex,
    runtime::{Runtime, Handle},
};

use crate::ipc_protocol::ServerConnection;

use super::{
    app::App,
    renderer::{
        Renderer,
        display_list::DisplayList,
    },
};

/// A custom event used to perform actions within the glutin event loop on the main thread
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum MainThreadAction {
    /// Redraw the window
    Redraw,
    /// Update the window title
    SetTitle(String),
    /// Update the window size (in logical coordinates)
    SetSize(LogicalSize<u32>),
    /// Change the maximized state of the window
    SetIsMaximized(bool),
    /// Change the fullscreen state of the window
    SetIsFullscreen(bool),
}

/// Run the renderer process in the current thread
///
/// This function must run in the main thread ONLY
pub fn main() {
    assert_main_thread();

    // The runtime for driving async code
    let runtime = Runtime::new()
        .expect("unable to spawn tokio runtime to run turtle server process");

    // The state of the drawing and the state/drawings associated with each turtle
    let app = Arc::new(App::default());
    // All of the drawing primitives in the order in which they wil be drawn
    //
    // This is managed separately from the rest of the app state because the display list is shared
    // among pretty much everything and so critical sections containing the display list need to be
    // as short as possible.
    let display_list = Arc::new(Mutex::new(DisplayList::default()));

    let event_loop = EventLoop::with_user_event();

    // Create the proxy that will be given to the thread managing IPC
    let event_loop_proxy = event_loop.create_proxy();

    let window_builder = {
        let drawing = runtime.handle().block_on(app.drawing_mut());
        WindowBuilder::new()
            .with_title(&drawing.title)
            .with_inner_size(LogicalSize {width: drawing.width, height: drawing.height})
    };

    // Create an OpenGL 3.x context for Pathfinder to use
    let gl_context = ContextBuilder::new()
        .with_gl(GlRequest::Latest)
        .with_gl_profile(GlProfile::Core)
        .with_vsync(true)
        .with_double_buffer(Some(true))
        .build_windowed(window_builder, &event_loop)
        .expect("bug: either could not create window or could not build OpenGL context");

    // Load OpenGL, and make the context current
    let gl_context = unsafe { gl_context.make_current().unwrap() };
    gl::load_with(|name| gl_context.get_proc_address(name) as *const _);

    // Need to draw using the physical size in pixels, not the logical size
    let draw_size = gl_context.window().inner_size();
    let mut renderer = Renderer::new(draw_size, gl_context.window().scale_factor());

    event_loop.run(move |event, _, control_flow| match event {
        GlutinEvent::NewEvents(StartCause::Init) => {
            // Spawn the actual server thread(s) that will handle incoming IPC messages and
            // asynchronous update the shared state
            //
            // Note that putting this code here instead of before the event loop causes the
            // `Turtle::new()`, etc. methods not to return before the window opens. Those methods
            // can't return because the connection handshake cannot complete before the thread used
            // for IPC is spawned.
            let handle = runtime.handle().clone();
            spawn_async_server(handle, app.clone(), display_list.clone(), event_loop_proxy.clone());
        },

        // Quit if the window is closed or if Esc is pressed and then released
        GlutinEvent::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } | GlutinEvent::WindowEvent {
            event: WindowEvent::Destroyed,
            ..
        } | GlutinEvent::DeviceEvent {
            event: DeviceEvent::Key(KeyboardInput {
                state: ElementState::Released,
                virtual_keycode: Some(VirtualKeyCode::Escape),
                ..
            }),
            ..
        } => {
            *control_flow = ControlFlow::Exit;
        },

        GlutinEvent::WindowEvent {
            event: WindowEvent::ScaleFactorChanged {scale_factor, ..},
            ..
        } => {
            renderer.set_scale_factor(scale_factor);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::WindowEvent {window_id, event} => {
            //TODO: Check if event modifies state and then redraw if necessary
        },
        GlutinEvent::DeviceEvent {device_id, event} => {
            //TODO: Check if event modifies state and then redraw if necessary
        },

        GlutinEvent::UserEvent(MainThreadAction::Redraw) => {
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetTitle(title)) => {
            gl_context.window().set_title(&title);
        },

        GlutinEvent::UserEvent(MainThreadAction::SetSize(size)) => {
            gl_context.window().set_inner_size(size);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsMaximized(is_maximized)) => {
            gl_context.window().set_maximized(is_maximized);
            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::UserEvent(MainThreadAction::SetIsFullscreen(is_fullscreen)) => {
            gl_context.window().set_fullscreen(if is_fullscreen {
                Some(Fullscreen::Borderless(gl_context.window().current_monitor()))
            } else { None });

            //TODO: No idea if this next line is necessary or not
            gl_context.window().request_redraw();
        },

        GlutinEvent::RedrawRequested(_) => {
            let handle = runtime.handle();
            handle.block_on(redraw(&app, &display_list, &gl_context, &mut renderer));
            *control_flow = ControlFlow::Wait;
        },

        _ => {},
    });
}

async fn redraw(
    app: &App,
    display_list: &Mutex<DisplayList>,
    gl_context: &WindowedContext<PossiblyCurrent>,
    renderer: &mut Renderer,
) {
    let drawing = {
        // Hold the drawing lock for as little time as possible
        let drawing = app.drawing_mut().await;
        drawing.clone()
    };

    // Locking the turtles before the display list to be consistent with all of the request
    // handlers. Inconsistent lock ordering can cause deadlock.
    let mut turtles = Vec::new();
    for id in app.turtle_ids().await {
        turtles.push(app.turtle(id).await);
    }
    // Very important to have all the data locked before rendering. Do not want renderer to have
    // to figure out how to lock.
    let mut locked_turtles = Vec::with_capacity(turtles.len());
    for turtle in &turtles {
        locked_turtles.push(turtle.lock().await);
    }
    // Renderer only needs (read-only) access to TurtleState
    // Doing this also decouples renderer code from runtime by not having to
    // know about the `MutexGuard` type in tokio
    let turtle_states = locked_turtles.iter().map(|t| &t.state);

    let display_list = display_list.lock().await;

    let draw_size = gl_context.window().inner_size();
    renderer.render(draw_size, &display_list, &drawing, turtle_states);
    gl_context.swap_buffers().expect("unable to swap the buffer (for double buffering)");
}

fn assert_main_thread() {
    // This check isn't foolproof. Someone can always create a thread named "main".
    if thread::current().name().unwrap_or("") != "main" {
        // In order to maintain compatibility with MacOS, we need to make sure that windows are
        // only created on the main thread. We do this check on all platforms so that no one
        // can accidentally make a change that creates the window off of the main thread.
        unreachable!("bug: windows can only be created on the main thread");
    }
}

fn spawn_async_server(
    handle: Handle,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: EventLoopProxy<MainThreadAction>,
) {
    // Spawn root task
    handle.spawn(async {
        let conn = ServerConnection::connect_stdin().await
            .expect("unable to establish turtle server connection");
        super::serve(conn, app, display_list, event_loop).await;
    });
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher};
use std::cmp::PartialEq;
use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use ncollide::query::{Contact, Proximity};
use nalgebra::Point2;
use glium::glutin::VirtualKeyCode;
use glium::glutin::MouseButton;

use engine::Engine;
use engine::entity::{Entity, EntityBuilder};
use engine::entity::component::PhysicsData;
use engine::util;
use engine::util::{HashMap, HashSet};

#[derive(Clone)]
pub enum InputState {
    Pressed,
    Released,
}

pub enum Event {
    Update(f32),
    Collision(usize, CollisionData),
    Proximity(usize, ProximityData),
    KeyInput(InputState, KeyCode),
    MouseMove((f32, f32)),
    MouseInput(InputState, MouseButton),
    Spawn,
    Timer(usize),
    CTimer(u8, usize),
    Render,
    Custom(Box<Any>),
}

use std::fmt;

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Update(_) => write!(f, "Update"),
            Event::Collision(_, _) => write!(f, "Collision"),
            Event::Proximity(_, _) => write!(f, "Proximity"),
            Event::KeyInput(_, _) => write!(f, "Key Input"),
            Event::MouseMove(_) => write!(f, "Mouse Movement"),
            Event::MouseInput(_, _) => write!(f, "Mouse Input"),
            Event::Spawn => write!(f, "Spawn"),
            Event::Timer(_) => write!(f, "Timer"),
            Event::CTimer(_, _) => write!(f, "CTimer"),
            Event::Render => write!(f, "Render"),
            Event::Custom(_) => write!(f, "Custom"),
        }
    }
}

pub enum EventType {
    Update,
    Collision,
    Proximity,
    KeyInput,
    MouseMove,
    MouseInput,
    Spawn,
    Timer,
    Render,
    Custom,
}

pub type KeyCode = VirtualKeyCode;

#[derive(Clone)]
pub struct CollisionData {
    pub contact: Contact<Point2<f32>>,
    pub this_object: Rc<PhysicsData>,
    pub other_object: Rc<PhysicsData>,
}

#[derive(Clone)]
pub struct ProximityData {
    pub proximity: Proximity,
    pub this_object: Rc<PhysicsData>,
    pub other_object: Rc<PhysicsData>,
}

pub enum SysEvent<E: Entity> {
    Destroy(usize),
    Create(Box<Fn(&Engine<E>) -> E>),
}

impl Hash for Event {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Event::Update(_) => state.write_u8(0),
            Event::Collision(_, _) => state.write_u8(1),
            Event::KeyInput(_, _) => state.write_u8(2),
            Event::MouseMove(_) => state.write_u8(3),
            Event::MouseInput(_, _) => state.write_u8(4),
            Event::Spawn => state.write_u8(5),
            Event::Proximity(_, _) => state.write_u8(6),
            Event::Timer(_) => state.write_u8(7),
            Event::Render => state.write_u8(8),
            Event::Custom(_) => state.write_u8(9),
            Event::CTimer(_, _) => state.write_u8(10),
        }
    }
}

impl Eq for Event {}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        match (self, other) {
            (&Event::Update(_), &Event::Update(_)) => true,
            (&Event::Collision(_, _), &Event::Collision(_, _)) => true,
            (&Event::Proximity(_, _), &Event::Proximity(_, _)) => true,
            (&Event::KeyInput(_, _), &Event::KeyInput(_, _)) => true,
            (&Event::MouseMove(_), &Event::MouseMove(_)) => true,
            (&Event::MouseInput(_, _), &Event::MouseInput(_, _)) => true,
            (&Event::Spawn, &Event::Spawn) => true,
            (&Event::Timer(_), &Event::Timer(_)) => true,
            (&Event::Render, &Event::Render) => true,
            (&Event::Custom(_), &Event::Custom(_)) => true,
            (&Event::CTimer(_, _), &Event::CTimer(_, _)) => true,
            _ => false,
        }
    }
}

pub struct Dispatcher {
    pub queue: Rc<RefCell<Vec<(usize, Rc<Event>)>>>,
}

impl Dispatcher {
    pub fn dispatch(&self, id: usize, e: Event) {
        self.queue.borrow_mut().push((id, Rc::new(e)));
    }
}

#[derive(Default)]
pub struct Handler<E: Entity> {
    subscriptions: HashMap<Event, HashSet<usize>>,
    pub queue: Rc<RefCell<Vec<(usize, Rc<Event>)>>>,
    sysqueue: Vec<SysEvent<E>>,
}

impl<E: Entity> Handler<E> {
    pub fn new() -> Handler<E> {
        Handler {
            sysqueue: vec![],
            queue: Rc::new(RefCell::new(vec![])),
            subscriptions: Default::default(),
        }
    }

    pub fn subscribe(&mut self, id: usize, event: Event) {
        if !self.subscriptions.contains_key(&event) {
            let mut set: HashSet<usize> = util::hashset();
            set.insert(id);
            self.subscriptions.insert(event, set);
        } else {
            self.subscriptions.get_mut(&event).unwrap().insert(id);
        }
    }

    pub fn unsubscribe(&mut self, id: usize, event: Event) {
        match self.subscriptions.get_mut(&event) {
            Some(subscribers) => {
                subscribers.remove(&id);
            }
            None => {}
        }
    }

    pub fn unsubscribe_all(&mut self, id: usize) {
        for (_, subs) in self.subscriptions.iter_mut() {
            subs.remove(&id);
        }
    }

    pub fn enqueue_all(&mut self, event: Event) {
        match self.subscriptions.get(&event) {
            Some(subscribers) => {
                let rc = Rc::new(event);
                for sub in subscribers {
                    self.queue.borrow_mut().push((sub.clone(), rc.clone()));
                }
            }
            None => {}
        }
    }

    pub fn enqueue_specific(&mut self, id: usize, event: Event) {
        self.queue.borrow_mut().push((id, Rc::new(event)));
    }

    pub fn enqueue_specific_rc(&mut self, id: usize, event: Rc<Event>) {
        self.queue.borrow_mut().push((id, event));
    }

    pub fn enqueue_sys(&mut self, event: SysEvent<E>) {
        self.sysqueue.push(event);
    }

    pub fn flush(&mut self) -> Vec<(usize, Rc<Event>)> {
        mem::replace(&mut self.queue.borrow_mut(), Default::default())
    }

    pub fn flush_sys(&mut self) -> Vec<SysEvent<E>> {
        mem::replace(&mut self.sysqueue, Default::default())
    }
}

#[test]
fn test_eventmap() {
    let mut evs = util::HashMap();
    evs.insert(Event::Update(0.0), 0);
    assert_eq!(evs.get(&Event::Update(1.0)).unwrap(), &0);
}
<commit_msg>Fix tests<commit_after>use std::hash::{Hash, Hasher};
use std::cmp::PartialEq;
use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use ncollide::query::{Contact, Proximity};
use nalgebra::Point2;
use glium::glutin::VirtualKeyCode;
use glium::glutin::MouseButton;

use engine::Engine;
use engine::entity::{Entity, EntityBuilder};
use engine::entity::component::PhysicsData;
use engine::util;
use engine::util::{HashMap, HashSet};

#[derive(Clone)]
pub enum InputState {
    Pressed,
    Released,
}

pub enum Event {
    Update(f32),
    Collision(usize, CollisionData),
    Proximity(usize, ProximityData),
    KeyInput(InputState, KeyCode),
    MouseMove((f32, f32)),
    MouseInput(InputState, MouseButton),
    Spawn,
    Timer(usize),
    CTimer(u8, usize),
    Render,
    Custom(Box<Any>),
}

use std::fmt;

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Update(_) => write!(f, "Update"),
            Event::Collision(_, _) => write!(f, "Collision"),
            Event::Proximity(_, _) => write!(f, "Proximity"),
            Event::KeyInput(_, _) => write!(f, "Key Input"),
            Event::MouseMove(_) => write!(f, "Mouse Movement"),
            Event::MouseInput(_, _) => write!(f, "Mouse Input"),
            Event::Spawn => write!(f, "Spawn"),
            Event::Timer(_) => write!(f, "Timer"),
            Event::CTimer(_, _) => write!(f, "CTimer"),
            Event::Render => write!(f, "Render"),
            Event::Custom(_) => write!(f, "Custom"),
        }
    }
}

pub enum EventType {
    Update,
    Collision,
    Proximity,
    KeyInput,
    MouseMove,
    MouseInput,
    Spawn,
    Timer,
    Render,
    Custom,
}

pub type KeyCode = VirtualKeyCode;

#[derive(Clone)]
pub struct CollisionData {
    pub contact: Contact<Point2<f32>>,
    pub this_object: Rc<PhysicsData>,
    pub other_object: Rc<PhysicsData>,
}

#[derive(Clone)]
pub struct ProximityData {
    pub proximity: Proximity,
    pub this_object: Rc<PhysicsData>,
    pub other_object: Rc<PhysicsData>,
}

pub enum SysEvent<E: Entity> {
    Destroy(usize),
    Create(Box<Fn(&Engine<E>) -> E>),
}

impl Hash for Event {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Event::Update(_) => state.write_u8(0),
            Event::Collision(_, _) => state.write_u8(1),
            Event::KeyInput(_, _) => state.write_u8(2),
            Event::MouseMove(_) => state.write_u8(3),
            Event::MouseInput(_, _) => state.write_u8(4),
            Event::Spawn => state.write_u8(5),
            Event::Proximity(_, _) => state.write_u8(6),
            Event::Timer(_) => state.write_u8(7),
            Event::Render => state.write_u8(8),
            Event::Custom(_) => state.write_u8(9),
            Event::CTimer(_, _) => state.write_u8(10),
        }
    }
}

impl Eq for Event {}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        match (self, other) {
            (&Event::Update(_), &Event::Update(_)) => true,
            (&Event::Collision(_, _), &Event::Collision(_, _)) => true,
            (&Event::Proximity(_, _), &Event::Proximity(_, _)) => true,
            (&Event::KeyInput(_, _), &Event::KeyInput(_, _)) => true,
            (&Event::MouseMove(_), &Event::MouseMove(_)) => true,
            (&Event::MouseInput(_, _), &Event::MouseInput(_, _)) => true,
            (&Event::Spawn, &Event::Spawn) => true,
            (&Event::Timer(_), &Event::Timer(_)) => true,
            (&Event::Render, &Event::Render) => true,
            (&Event::Custom(_), &Event::Custom(_)) => true,
            (&Event::CTimer(_, _), &Event::CTimer(_, _)) => true,
            _ => false,
        }
    }
}

pub struct Dispatcher {
    pub queue: Rc<RefCell<Vec<(usize, Rc<Event>)>>>,
}

impl Dispatcher {
    pub fn dispatch(&self, id: usize, e: Event) {
        self.queue.borrow_mut().push((id, Rc::new(e)));
    }
}

#[derive(Default)]
pub struct Handler<E: Entity> {
    subscriptions: HashMap<Event, HashSet<usize>>,
    pub queue: Rc<RefCell<Vec<(usize, Rc<Event>)>>>,
    sysqueue: Vec<SysEvent<E>>,
}

impl<E: Entity> Handler<E> {
    pub fn new() -> Handler<E> {
        Handler {
            sysqueue: vec![],
            queue: Rc::new(RefCell::new(vec![])),
            subscriptions: Default::default(),
        }
    }

    pub fn subscribe(&mut self, id: usize, event: Event) {
        if !self.subscriptions.contains_key(&event) {
            let mut set: HashSet<usize> = util::hashset();
            set.insert(id);
            self.subscriptions.insert(event, set);
        } else {
            self.subscriptions.get_mut(&event).unwrap().insert(id);
        }
    }

    pub fn unsubscribe(&mut self, id: usize, event: Event) {
        match self.subscriptions.get_mut(&event) {
            Some(subscribers) => {
                subscribers.remove(&id);
            }
            None => {}
        }
    }

    pub fn unsubscribe_all(&mut self, id: usize) {
        for (_, subs) in self.subscriptions.iter_mut() {
            subs.remove(&id);
        }
    }

    pub fn enqueue_all(&mut self, event: Event) {
        match self.subscriptions.get(&event) {
            Some(subscribers) => {
                let rc = Rc::new(event);
                for sub in subscribers {
                    self.queue.borrow_mut().push((sub.clone(), rc.clone()));
                }
            }
            None => {}
        }
    }

    pub fn enqueue_specific(&mut self, id: usize, event: Event) {
        self.queue.borrow_mut().push((id, Rc::new(event)));
    }

    pub fn enqueue_specific_rc(&mut self, id: usize, event: Rc<Event>) {
        self.queue.borrow_mut().push((id, event));
    }

    pub fn enqueue_sys(&mut self, event: SysEvent<E>) {
        self.sysqueue.push(event);
    }

    pub fn flush(&mut self) -> Vec<(usize, Rc<Event>)> {
        mem::replace(&mut self.queue.borrow_mut(), Default::default())
    }

    pub fn flush_sys(&mut self) -> Vec<SysEvent<E>> {
        mem::replace(&mut self.sysqueue, Default::default())
    }
}

#[test]
fn test_eventmap() {
    let mut evs = util::hashmap();
    evs.insert(Event::Update(0.0), 0);
    assert_eq!(evs.get(&Event::Update(1.0)).unwrap(), &0);
}
<|endoftext|>


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

use std::mem::size_of;

enum Ei8 {
    Ai8 = -1,
    Bi8 = 0
}

enum Eu8 {
    Au8 = 0,
    Bu8 = 0x80
}

enum Ei16 {
    Ai16 = -1,
    Bi16 = 0x80
}

enum Eu16 {
    Au16 = 0,
    Bu16 = 0x8000
}

enum Ei32 {
    Ai32 = -1,
    Bi32 = 0x8000
}

enum Eu32 {
    Au32 = 0,
    Bu32 = 0x8000_0000
}

enum Ei64 {
    Ai64 = -1,
    Bi64 = 0x8000_0000
}

enum Eu64 {
    Au64 = 0,
    Bu64 = 0x8000_0000_0000_0000
}

pub fn main() {
    assert_eq!(size_of::<Ei8>(), 1);
    assert_eq!(size_of::<Eu8>(), 1);
    assert_eq!(size_of::<Ei16>(), 2);
    assert_eq!(size_of::<Eu16>(), 2);
    assert_eq!(size_of::<Ei32>(), 4);
    assert_eq!(size_of::<Eu32>(), 4);
    assert_eq!(size_of::<Ei64>(), 8);
    assert_eq!(size_of::<Eu64>(), 8);
}
<commit_msg>break enum variant discriminant inference in case of 32-bit<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(stmt_expr_attributes)]

use std::mem::size_of;

enum Ei8 {
    Ai8 = -1,
    Bi8 = 0
}

enum Eu8 {
    Au8 = 0,
    Bu8 = 0x80
}

enum Ei16 {
    Ai16 = -1,
    Bi16 = 0x80
}

enum Eu16 {
    Au16 = 0,
    Bu16 = 0x8000
}

enum Ei32 {
    Ai32 = -1,
    Bi32 = 0x8000
}

enum Eu32 {
    Au32 = 0,
    Bu32 = 0x8000_0000
}

enum Ei64 {
    Ai64 = -1,
    Bi64 = 0x8000_0000
}

pub fn main() {
    assert_eq!(size_of::<Ei8>(), 1);
    assert_eq!(size_of::<Eu8>(), 1);
    assert_eq!(size_of::<Ei16>(), 2);
    assert_eq!(size_of::<Eu16>(), 2);
    assert_eq!(size_of::<Ei32>(), 4);
    assert_eq!(size_of::<Eu32>(), 4);
    #[cfg(target_pointer_width = "64")]
    assert_eq!(size_of::<Ei64>(), 8);
    #[cfg(target_pointer_width = "32")]
    assert_eq!(size_of::<Ei64>(), 4);
}
<|endoftext|>


<commit_before>// compile-pass

// Test that we can handle newtypes wrapping extern types

#![feature(extern_types, const_transmute)]

extern "C" {
  pub type ExternType;
}
unsafe impl Sync for ExternType {}

#[repr(transparent)]
pub struct Wrapper(ExternType);

static MAGIC_FFI_STATIC: u8 = 42;

pub static MAGIC_FFI_REF: &'static Wrapper = unsafe {
  std::mem::transmute(&MAGIC_FFI_STATIC)
};

fn main() {}
<commit_msg>also test with PhantomData<commit_after>// compile-pass

// Test that we can handle newtypes wrapping extern types

#![feature(extern_types, const_transmute)]

use std::marker::PhantomData;

extern "C" {
  pub type ExternType;
}
unsafe impl Sync for ExternType {}
static MAGIC_FFI_STATIC: u8 = 42;

#[repr(transparent)]
pub struct Wrapper(ExternType);
pub static MAGIC_FFI_REF: &'static Wrapper = unsafe {
  std::mem::transmute(&MAGIC_FFI_STATIC)
};

#[repr(transparent)]
pub struct Wrapper2(PhantomData<Vec<i32>>, ExternType);
pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe {
  std::mem::transmute(&MAGIC_FFI_STATIC)
};

fn main() {}
<|endoftext|>


<commit_before>use db::database::{Database, QueryResult};
use db::schema::Type;

#[test]
fn real_db_insert_parsing() {
    let mut db = Database::new();
    {
        let mut stream = db.create_stream("users").unwrap();
        stream.schema.add_type("age", Type::String);
    }

    let q = r"INSERT INTO users set age=1;";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 0);
    } else {
        panic!("Everything on fire");
    }

    let q = r"INSERT INTO users set age=2;";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 1);
    } else {
        panic!("Everything on fire");
    }
}

#[test]
fn test_quoted_string_insert() {

    let mut db = Database::new();
    {
        let mut stream = db.create_stream("users").unwrap();
        stream.schema.add_type("age", Type::String);
    }

    let q= "INSERT INTO users set name='Jon';";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 1);
    } else {
        panic!("Everything on fire");
    }
}

#[test]
fn define_stream_test() {
    let query = r#""#;
}<commit_msg>double quoted strings works<commit_after>use db::database::{Database, QueryResult};
use db::schema::Type;

#[test]
fn real_db_insert_parsing() {
    let mut db = Database::new();
    {
        let mut stream = db.create_stream("users").unwrap();
        stream.schema.add_type("age", Type::String);
    }

    let q = r"INSERT INTO users set age=1;";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 0);
    } else {
        panic!("Everything on fire");
    }

    let q = r"INSERT INTO users set age=2;";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 1);
    } else {
        panic!("Everything on fire");
    }
}

#[test]
fn test_quoted_string_insert() {

    let mut db = Database::new();
    {
        let mut stream = db.create_stream("users").unwrap();
        stream.schema.add_type("name", Type::String);
    }

    let q= "INSERT INTO users set name='Jon';";
    if let QueryResult::Insert(result) = db.execute(q).unwrap() {
        assert_eq!(result, 0);
    } else {
        panic!("Everything on fire");
    }
}

#[test]
fn define_stream_test() {
    let query = r#""#;
}<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/_template_procedural_macro_meta/latest/_template_procedural_macro_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! Protocol of modularity unifying interface of a module.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

mod impls;

///
/// Protocol of modularity unifying interface of a module.
///

#[ proc_macro ]
pub fn procedural_macro( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = impls::impls( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<commit_msg>Remove extra directives from `*_meta` modules<commit_after>// #![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/_template_procedural_macro_meta/latest/_template_procedural_macro_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! Protocol of modularity unifying interface of a module.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

mod impls;

///
/// Protocol of modularity unifying interface of a module.
///

#[ proc_macro ]
pub fn procedural_macro( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = impls::impls( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<|endoftext|>


<commit_before>//! Create window.

use collections::deque::Deque;
use collections::ringbuf::RingBuf;
// External crates.
use glfw;
// Local crate.
use game_window::{
    event,
    keycode,
    GameWindow,
};
use game_window_settings::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    glfw: glfw::Glfw,
    /// Game window settings;
    settings: GameWindowSettings,

    should_close: bool,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    fn flush_messages(&mut self) {
        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.should_close = true;
                },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(event::KeyPressEvent(glfw_keycode_to_keycode(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(event::KeyReleaseEvent(glfw_keycode_to_keycode(key)));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Create GLFW window.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title, glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.make_current();

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,

            should_close: false,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn poll_event(&mut self) -> event::Event {
        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            self.flush_messages();
            if self.event_queue.len() != 0 {
                self.poll_event()
            } else {
                event::NoEvent
            }
        }
    }
}

fn glfw_keycode_to_keycode(keycode: glfw::Key) -> keycode::KeyCode {
    match keycode {
        glfw::KeySpace => keycode::SpaceKey,
        glfw::KeyEnter => keycode::EnterKey,
        glfw::KeyUp => keycode::UpKey,
        glfw::KeyDown => keycode::DownKey,
        glfw::KeyLeft => keycode::LeftKey,
        glfw::KeyRight => keycode::RightKey,
        _ => keycode::UnknownKey,
    }
}
<commit_msg>Updated `poll_event` of `GameWindowGLFW`<commit_after>//! Create window.

use collections::deque::Deque;
use collections::ringbuf::RingBuf;
// External crates.
use glfw;
// Local crate.
use game_window::{
    event,
    keycode,
    GameWindow,
};
use game_window_settings::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    glfw: glfw::Glfw,
    /// Game window settings;
    settings: GameWindowSettings,

    should_close: bool,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.should_close = true;
                },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(event::KeyPressEvent(glfw_keycode_to_keycode(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(event::KeyReleaseEvent(glfw_keycode_to_keycode(key)));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Create GLFW window.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title, glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.make_current();

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,

            should_close: false,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_keycode_to_keycode(keycode: glfw::Key) -> keycode::KeyCode {
    match keycode {
        glfw::KeySpace => keycode::SpaceKey,
        glfw::KeyEnter => keycode::EnterKey,
        glfw::KeyUp => keycode::UpKey,
        glfw::KeyDown => keycode::DownKey,
        glfw::KeyLeft => keycode::LeftKey,
        glfw::KeyRight => keycode::RightKey,
        _ => keycode::UnknownKey,
    }
}
<|endoftext|>


<commit_before>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc::mir;
use rustc::ty::layout::LayoutOf;
use rustc::mir::interpret::{InterpResult, Scalar, PointerArithmetic};

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
        Offset | Shl | Shr =>
            true,
        Eq | Ne | Lt | Le | Gt | Ge =>
            false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
        Eq | Ne | Lt | Le | Gt | Ge =>
            true,
        Offset | Shl | Shr =>
            false,
    }
}

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = match self.frame().block {
            Some(block) => block,
            None => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true)
            }
        };
        let stmt_id = self.frame().stmt;
        let body = self.body();
        let basic_block = &body.basic_blocks()[block];

        let old_frames = self.cur_frame();

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            assert_eq!(old_frames, self.cur_frame());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.cur_frame());
        self.terminator(terminator)?;
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.cur_frame();
        self.tcx.span = stmt.source_info.span;
        self.memory.tcx.span = stmt.source_info.span;

        match stmt.kind {
            Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,

            SetDiscriminant {
                ref place,
                variant_index,
            } => {
                let dest = self.eval_place(place)?;
                self.write_discriminant_index(variant_index, dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                let old_val = self.storage_live(local)?;
                self.deallocate_local(old_val)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                let old_val = self.storage_dead(local);
                self.deallocate_local(old_val)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, ref place) => {
                let dest = self.eval_place(place)?;
                M::retag(self, kind, dest)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack[frame_idx].stmt += 1;
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: &mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc::mir::Rvalue::*;
        match *rvalue {
            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(op, dest)?;
            }

            BinaryOp(bin_op, ref left, ref right) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(
                    bin_op,
                    left,
                    right,
                    dest,
                )?;
            }

            CheckedBinaryOp(bin_op, ref left, ref right) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(
                    bin_op,
                    left,
                    right,
                    dest,
                )?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant_index(variant_index, dest)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(dest, variant_index)?, active_field_index)
                        } else {
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None)
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    // Ignore zero-sized fields.
                    if !op.layout.is_zst() {
                        let field_index = active_field_index.unwrap_or(i);
                        let field_dest = self.place_field(dest, field_index as u64)?;
                        self.copy_op(op, field_dest)?;
                    }
                }
            }

            Repeat(ref operand, _) => {
                let op = self.eval_operand(operand, None)?;
                let dest = self.force_allocation(dest)?;
                let length = dest.len(self)?;

                if let Some(first_ptr) = self.check_mplace_access(dest, None)? {
                    // Write the first.
                    let first = self.mplace_field(dest, 0)?;
                    self.copy_op(op, first.into())?;

                    if length > 1 {
                        let elem_size = first.layout.size;
                        // Copy the rest. This is performance-sensitive code
                        // for big static/const arrays!
                        let rest_ptr = first_ptr.offset(elem_size, self)?;
                        self.memory.copy_repeatedly(
                            first_ptr, rest_ptr, elem_size, length - 1, /*nonoverlapping:*/true
                        )?;
                    }
                }
            }

            Len(ref place) => {
                // FIXME(CTFE): don't allow computing the length of arrays in const eval
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(src)?;
                let len = mplace.len(self)?;
                let size = self.pointer_size();
                self.write_scalar(
                    Scalar::from_uint(len, size),
                    dest,
                )?;
            }

            Ref(_, _, ref place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(src)?;
                if place.layout.size.bytes() > 0 {
                    // definitely not a ZST
                    assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                }
                self.write_immediate(place.to_ref(), dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, dest)?;
            }

            NullaryOp(mir::NullOp::SizeOf, ty) => {
                let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                assert!(!layout.is_unsized(),
                        "SizeOf nullary MIR operator called for unsized type");
                let size = self.pointer_size();
                self.write_scalar(
                    Scalar::from_uint(layout.size.bytes(), size),
                    dest,
                )?;
            }

            Cast(kind, ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                self.cast(src, kind, dest)?;
            }

            Discriminant(ref place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(op)?.0;
                let size = dest.layout.size;
                self.write_scalar(Scalar::from_uint(discr_val, size), dest)?;
            }
        }

        self.dump_place(*dest);

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);
        self.tcx.span = terminator.source_info.span;
        self.memory.tcx.span = terminator.source_info.span;

        let old_stack = self.cur_frame();
        let old_bb = self.frame().block;

        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            // This should change *something*
            debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
            info!("// {:?}", self.frame().block);
        }
        Ok(())
    }
}
<commit_msg>fix miri step debug printing<commit_after>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc::mir;
use rustc::ty::layout::LayoutOf;
use rustc::mir::interpret::{InterpResult, Scalar, PointerArithmetic};

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
        Offset | Shl | Shr =>
            true,
        Eq | Ne | Lt | Le | Gt | Ge =>
            false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
        Eq | Ne | Lt | Le | Gt | Ge =>
            true,
        Offset | Shl | Shr =>
            false,
    }
}

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = match self.frame().block {
            Some(block) => block,
            None => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true)
            }
        };
        let stmt_id = self.frame().stmt;
        let body = self.body();
        let basic_block = &body.basic_blocks()[block];

        let old_frames = self.cur_frame();

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            assert_eq!(old_frames, self.cur_frame());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.cur_frame());
        self.terminator(terminator)?;
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.cur_frame();
        self.tcx.span = stmt.source_info.span;
        self.memory.tcx.span = stmt.source_info.span;

        match stmt.kind {
            Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,

            SetDiscriminant {
                ref place,
                variant_index,
            } => {
                let dest = self.eval_place(place)?;
                self.write_discriminant_index(variant_index, dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                let old_val = self.storage_live(local)?;
                self.deallocate_local(old_val)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                let old_val = self.storage_dead(local);
                self.deallocate_local(old_val)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, ref place) => {
                let dest = self.eval_place(place)?;
                M::retag(self, kind, dest)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack[frame_idx].stmt += 1;
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: &mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc::mir::Rvalue::*;
        match *rvalue {
            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(op, dest)?;
            }

            BinaryOp(bin_op, ref left, ref right) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(
                    bin_op,
                    left,
                    right,
                    dest,
                )?;
            }

            CheckedBinaryOp(bin_op, ref left, ref right) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(
                    bin_op,
                    left,
                    right,
                    dest,
                )?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant_index(variant_index, dest)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(dest, variant_index)?, active_field_index)
                        } else {
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None)
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    // Ignore zero-sized fields.
                    if !op.layout.is_zst() {
                        let field_index = active_field_index.unwrap_or(i);
                        let field_dest = self.place_field(dest, field_index as u64)?;
                        self.copy_op(op, field_dest)?;
                    }
                }
            }

            Repeat(ref operand, _) => {
                let op = self.eval_operand(operand, None)?;
                let dest = self.force_allocation(dest)?;
                let length = dest.len(self)?;

                if let Some(first_ptr) = self.check_mplace_access(dest, None)? {
                    // Write the first.
                    let first = self.mplace_field(dest, 0)?;
                    self.copy_op(op, first.into())?;

                    if length > 1 {
                        let elem_size = first.layout.size;
                        // Copy the rest. This is performance-sensitive code
                        // for big static/const arrays!
                        let rest_ptr = first_ptr.offset(elem_size, self)?;
                        self.memory.copy_repeatedly(
                            first_ptr, rest_ptr, elem_size, length - 1, /*nonoverlapping:*/true
                        )?;
                    }
                }
            }

            Len(ref place) => {
                // FIXME(CTFE): don't allow computing the length of arrays in const eval
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(src)?;
                let len = mplace.len(self)?;
                let size = self.pointer_size();
                self.write_scalar(
                    Scalar::from_uint(len, size),
                    dest,
                )?;
            }

            Ref(_, _, ref place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(src)?;
                if place.layout.size.bytes() > 0 {
                    // definitely not a ZST
                    assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                }
                self.write_immediate(place.to_ref(), dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, dest)?;
            }

            NullaryOp(mir::NullOp::SizeOf, ty) => {
                let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                assert!(!layout.is_unsized(),
                        "SizeOf nullary MIR operator called for unsized type");
                let size = self.pointer_size();
                self.write_scalar(
                    Scalar::from_uint(layout.size.bytes(), size),
                    dest,
                )?;
            }

            Cast(kind, ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                self.cast(src, kind, dest)?;
            }

            Discriminant(ref place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(op)?.0;
                let size = dest.layout.size;
                self.write_scalar(Scalar::from_uint(discr_val, size), dest)?;
            }
        }

        self.dump_place(*dest);

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);
        self.tcx.span = terminator.source_info.span;
        self.memory.tcx.span = terminator.source_info.span;

        let old_stack = self.cur_frame();
        let old_bb = self.frame().block;

        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            // This should change *something*
            debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
            if let Some(block) = self.frame().block {
                info!("// executing {:?}", block);
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Buffer whose content is read-written by the GPU only.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
//! write simultaneously, or write and write simultaneously will block with a semaphore.

use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use smallvec::SmallVec;

use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
use buffer::traits::TypedBuffer;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

use OomError;
use SafeDeref;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A::Alloc,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this buffer is locked on the GPU side.
    gpu_lock: AtomicUsize,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> DeviceLocalBuffer<T> {
    /// Builds a new buffer. Only allowed for sized data.
    #[inline]
    pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T> DeviceLocalBuffer<[T]> {
    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T: ?Sized> DeviceLocalBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
                             -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!()        // We don't use sparse binding, therefore the other
                                                // errors can't happen
            }
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        try!(buffer.bind_memory(mem.memory(), mem.offset()));

        Ok(Arc::new(DeviceLocalBuffer {
            inner: buffer,
            memory: mem,
            queue_families: queue_families,
            gpu_lock: AtomicUsize::new(0),
            marker: PhantomData,
        }))
    }
}

impl<T: ?Sized, A> DeviceLocalBuffer<T, A> where A: MemoryPool {
    /// Returns the device used to create this buffer.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }

    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families.iter().map(|&num| {
            self.device().physical_device().queue_family_by_id(num).unwrap()
        }).collect()
    }
}

/// Access to a device local buffer.
// FIXME: add destructor
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocalBufferAccess
(P);

unsafe impl<T: ?Sized, A> Buffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Access = DeviceLocalBufferAccess<Arc<DeviceLocalBuffer<T, A>>>;

    #[inline]
    fn access(self) -> Self::Access {
        DeviceLocalBufferAccess(self)
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }
}

unsafe impl<T: ?Sized, A> TypedBuffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 BufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.0.inner,
            offset: 0,
        }
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        if val == 1 {
            true
        } else {
            self.0.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            false
        }
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);
    }
}

unsafe impl
 TypedBufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 DeviceOwned for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.0.inner.device()
    }
}
<commit_msg>Implement conflict_key for DeviceLocalBuffer<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Buffer whose content is read-written by the GPU only.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
//! write simultaneously, or write and write simultaneously will block with a semaphore.

use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use smallvec::SmallVec;

use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
use buffer::traits::TypedBuffer;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

use OomError;
use SafeDeref;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A::Alloc,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this buffer is locked on the GPU side.
    gpu_lock: AtomicUsize,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> DeviceLocalBuffer<T> {
    /// Builds a new buffer. Only allowed for sized data.
    #[inline]
    pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T> DeviceLocalBuffer<[T]> {
    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T: ?Sized> DeviceLocalBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
                             -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!()        // We don't use sparse binding, therefore the other
                                                // errors can't happen
            }
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        try!(buffer.bind_memory(mem.memory(), mem.offset()));

        Ok(Arc::new(DeviceLocalBuffer {
            inner: buffer,
            memory: mem,
            queue_families: queue_families,
            gpu_lock: AtomicUsize::new(0),
            marker: PhantomData,
        }))
    }
}

impl<T: ?Sized, A> DeviceLocalBuffer<T, A> where A: MemoryPool {
    /// Returns the device used to create this buffer.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }

    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families.iter().map(|&num| {
            self.device().physical_device().queue_family_by_id(num).unwrap()
        }).collect()
    }
}

/// Access to a device local buffer.
// FIXME: add destructor
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocalBufferAccess
(P);

unsafe impl<T: ?Sized, A> Buffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Access = DeviceLocalBufferAccess<Arc<DeviceLocalBuffer<T, A>>>;

    #[inline]
    fn access(self) -> Self::Access {
        DeviceLocalBufferAccess(self)
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }
}

unsafe impl<T: ?Sized, A> TypedBuffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 BufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.0.inner,
            offset: 0,
        }
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        self.0.inner.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        if val == 1 {
            true
        } else {
            self.0.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            false
        }
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);
    }
}

unsafe impl
 TypedBufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 DeviceOwned for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.0.inner.device()
    }
}
<|endoftext|>