libdrm 0.0.2

A reimplementation of the libdrm middleware library
Documentation
use drm_sys::*;
use super::super::util::*;
use super::super::result::*;

use std::os::unix::io::AsRawFd;
use std::slice::from_raw_parts_mut;
use libc;

#[derive(Debug, Clone, Copy)]
pub struct BufferId(pub RawId);

#[derive(Debug)]
pub struct DumbBuffer<'a, T> where T: 'a + AsRawFd + Sized {
    device: &'a T,
    id: BufferId,
    size: (u32, u32),
    bpp: u8,
    pitch: u32,
    length: u64
}

#[derive(Debug)]
pub struct DumbMapping<'a, T> where T: 'a + AsRawFd + Sized {
    buffer: &'a DumbBuffer<'a, T>,
    slice: &'a mut [u8]
}

impl<'a, T> DumbBuffer<'a, T> where T: AsRawFd {
    pub fn new(device: &'a T, size: (u16, u16), bpp: u8) -> Result<DumbBuffer<'a, T>> {
        let mut raw: drm_mode_create_dumb = Default::default();
        raw.width = size.0 as u32;
        raw.height = size.1 as u32;
        raw.bpp = bpp as u32;
        ioctl!(device, MACRO_DRM_IOCTL_MODE_CREATE_DUMB, &mut raw);

        let db = DumbBuffer {
            device: device,
            id: BufferId(raw.handle),
            size: (raw.width, raw.height),
            bpp: raw.bpp as u8,
            pitch: raw.pitch,
            length: raw.size
        };

        Ok(db)
    }

    pub fn map(&'a self) -> Result<DumbMapping<'a, T>> {
        let mut raw: drm_mode_map_dumb = Default::default();
        raw.handle = self.id.0;
        ioctl!(self.device, MACRO_DRM_IOCTL_MODE_MAP_DUMB, &mut raw);

        let ptr = unsafe {
            let base = 0 as *mut _;
            let length = self.length as usize;
            let prot = libc::PROT_READ | libc::PROT_WRITE;
            let flags = libc::MAP_SHARED;
            let fd = self.device.as_raw_fd();
            libc::mmap(base, length, prot, flags, fd, raw.offset as i64)
        } as *mut _;

        let slice = unsafe { from_raw_parts_mut(ptr, self.length as usize) };

        let map = DumbMapping {
            buffer: self,
            slice: slice
        };

        Ok(map)
    }

    pub fn remove(&mut self) -> Result<()> {
        let mut raw: drm_mode_destroy_dumb = Default::default();
        raw.handle = self.id.0;
        ioctl!(self.device, MACRO_DRM_IOCTL_MODE_DESTROY_DUMB, &mut raw);
        Ok(())
    }
}

#[cfg(not(debug_assertions))]
impl<'a, T> Drop for DumbBuffer<'a, T> where T: AsRawFd {
    fn drop(&mut self) {
        self.remove();
    }
}

#[cfg(debug_assertions)]
impl<'a, T> Drop for DumbBuffer<'a, T> where T: AsRawFd {
    fn drop(&mut self) {
        self.remove().unwrap();
    }
}

impl<'a, T> DumbMapping<'a, T> where T: 'a + AsRawFd + Sized {
    pub fn as_slice<'b>(&'b mut self) -> &'b mut [u8] {
        self.slice
    }

    pub fn remove(&mut self) -> Result<()> {
        let res = unsafe {
            libc::munmap(self.slice.as_mut_ptr() as *mut _, self.slice.len())
        };

        match res {
            0 => Ok(()),
            _ => Err(IoctlError::last_os_error().into())
        }
    }
}

#[cfg(not(debug_assertions))]
impl<'a, T> Drop for DumbMapping<'a, T> where T: AsRawFd {
    fn drop(&mut self) {
        self.remove();
    }
}

#[cfg(debug_assertions)]
impl<'a, T> Drop for DumbMapping<'a, T> where T: AsRawFd {
    fn drop(&mut self) {
        self.remove().unwrap();
    }
}

pub trait Buffer {
    fn size(&self) -> (u32, u32);
    fn pitch(&self) -> u32;
    fn bpp(&self) -> u8;
    fn depth(&self) -> u32;
    fn handle(&self) -> BufferId;
}

impl<'a, T> Buffer for DumbBuffer<'a, T> where T: AsRawFd {
    fn size(&self) -> (u32, u32) {
        self.size
    }

    fn pitch(&self) -> u32 {
        self.pitch
    }

    fn bpp(&self) -> u8 {
        self.bpp
    }

    fn depth(&self) -> u32 {
        24
    }

    fn handle(&self) -> BufferId {
        self.id
    }
}