#![deny(missing_docs, missing_copy_implementations)]
use std::error::Error as StdError;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::MutexGuard;
use Resources;
use {memory, buffer, handle};
#[doc(hidden)]
pub trait Gate<R: Resources> {
unsafe fn set<T>(&self, index: usize, val: T);
unsafe fn slice<'a, 'b, T>(&'a self, len: usize) -> &'b [T];
unsafe fn mut_slice<'a, 'b, T>(&'a self, len: usize) -> &'b mut [T];
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Error {
InvalidAccess(memory::Access, memory::Usage),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidAccess(ref access, ref usage) => {
write!(f, "{}: access = {:?}, usage = {:?}", self.description(), access, usage)
}
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
"The requested mapping access did not match the expected usage"
}
}
fn valid_access(access: memory::Access, usage: memory::Usage) -> Result<(), Error> {
use memory::Usage::*;
match usage {
Upload if access == memory::WRITE => Ok(()),
Download if access == memory::READ => Ok(()),
_ => Err(Error::InvalidAccess(access, usage)),
}
}
#[doc(hidden)]
pub unsafe fn read<R, T, S>(buffer: &buffer::Raw<R>, sync: S)
-> Result<Reader<R, T>, Error>
where R: Resources, T: Copy, S: FnOnce(&mut R::Mapping)
{
try!(valid_access(memory::READ, buffer.get_info().usage));
let mut mapping = buffer.lock_mapping().unwrap();
sync(&mut mapping);
Ok(Reader {
slice: mapping.slice(buffer.len::<T>()),
mapping: mapping,
})
}
#[doc(hidden)]
pub unsafe fn write<R, T, S>(buffer: &buffer::Raw<R>, sync: S)
-> Result<Writer<R, T>, Error>
where R: Resources, T: Copy, S: FnOnce(&mut R::Mapping)
{
try!(valid_access(memory::WRITE, buffer.get_info().usage));
let mut mapping = buffer.lock_mapping().unwrap();
sync(&mut mapping);
Ok(Writer {
slice: mapping.mut_slice(buffer.len::<T>()),
mapping: mapping,
})
}
pub struct Reader<'a, R: Resources, T: 'a + Copy> {
slice: &'a [T],
#[allow(dead_code)] mapping: MutexGuard<'a, R::Mapping>,
}
impl<'a, R: Resources, T: 'a + Copy> Deref for Reader<'a, R, T> {
type Target = [T];
fn deref(&self) -> &[T] { self.slice }
}
pub struct Writer<'a, R: Resources, T: 'a + Copy> {
slice: &'a mut [T],
#[allow(dead_code)] mapping: MutexGuard<'a, R::Mapping>,
}
impl<'a, R: Resources, T: 'a + Copy> Deref for Writer<'a, R, T> {
type Target = [T];
fn deref(&self) -> &[T] { &*self.slice }
}
impl<'a, R: Resources, T: 'a + Copy> DerefMut for Writer<'a, R, T> {
fn deref_mut(&mut self) -> &mut [T] { self.slice }
}
#[derive(Debug, PartialEq, Eq, Hash)]
#[doc(hidden)]
pub struct Status<R: Resources> {
cpu_wrote: bool,
gpu_access: Option<handle::Fence<R>>,
}
#[doc(hidden)]
impl<R: Resources> Status<R> {
pub fn clean() -> Self {
Status {
cpu_wrote: false,
gpu_access: None,
}
}
pub fn cpu_access<F>(&mut self, wait_fence: F)
where F: FnOnce(handle::Fence<R>)
{
self.gpu_access.take().map(wait_fence);
}
pub fn cpu_write_access<F>(&mut self, wait_fence: F)
where F: FnOnce(handle::Fence<R>)
{
self.cpu_access(wait_fence);
self.cpu_wrote = true;
}
pub fn gpu_access(&mut self, fence: handle::Fence<R>) {
self.gpu_access = Some(fence);
}
pub fn ensure_flushed<F>(&mut self, flush: F)
where F: FnOnce()
{
if self.cpu_wrote {
flush();
self.cpu_wrote = false;
}
}
}