open-cl-low-level 0.2.1

OpenCL low-level bindings
Documentation
use std::convert::TryInto;

use crate::ffi::{clWaitForEvents, cl_event};
use crate::{
    build_output,
    ClEvent,
    EventPtr, // Error, EventPtr, cl_release_event,
    Output,
};

/// The low-level function for synchronously waiting events (blocks the calling thread).
///
/// # Safety
/// Due to call to OpenCL's FFI with raw pointer (or slice of raw pointers) this call will cause
/// undefined behavior if any of the events is not in correct state, if the context of the events
/// has been freed, if any of the events is a null pointer, if the queue the event was created with
/// is freed, and a plethora of other conditions.
pub unsafe fn cl_wait_for_events<'a>(wl: &'a [cl_event]) -> Output<()> {
    build_output((), clWaitForEvents(wl.waitlist_len(), wl.waitlist_ptr()))
}

/// The low level trait for synchronously waiting for events.
///
/// # Safety
/// Due to multiple dangerous memory safety concerns with using events this
/// trait and it's functions are all unsafe. Mismanagement of the reference count,
/// lifetime, context, or resuse of an event is undefined behavior.
pub unsafe trait Waitlist: Sized {
    /// Copies the waitlist's (self) events into the passed mutable vector.
    ///
    /// # Safety
    /// Due to the movement of cl_event from one container to another, this function is unsafe
    /// failure to correctly track reference counts of cl_event objects can lead to memory leaks and/or
    /// segfaults.
    ///
    /// Note: When the vec that the events are given to Drops these events will not be released.
    unsafe fn fill_waitlist(&self, wl: &mut Vec<cl_event>);

    /// Consumes the waitlist into a vector of cl_events.
    ///
    /// # Safety
    /// Due to the movement of cl_event from one container to another, this function is unsafe
    /// failure to correctly track reference counts of cl_event objects can lead to memory leaks and/or
    /// segfaults.
    ///
    /// Note: When the vec that the events are given to Drops these events will not be released.
    unsafe fn new_waitlist(&self) -> Vec<cl_event>;

    /// Synchronously waits (blocks the thread) until all events in the waitlist are complete.
    ///
    /// # Safety
    /// Due to call to OpenCL's FFI with raw pointer (or Vec of raw pointers) this call will cause
    /// undefined behavior if any of the events is not in correct state, if the context of the events
    /// has been freed, if any of the events is a null pointer, if the queue the event was created with
    /// is freed, and a plethora of other conditions.
    ///
    /// Note: When the vec that the events are given to Drops these events will not be released.
    unsafe fn wait(self) -> Output<()> {
        let mut waitlist = Vec::new();
        self.fill_waitlist(&mut waitlist);
        cl_wait_for_events(&waitlist[..])
    }
}

/// This trait is used to produce the required size and pointer arguments to the FFI of OpenCL
/// allowing for the synchronously waiting of a given event before execution is allowed to proceed.
///
/// # Safety
/// Due to this trait and it's only function involving the use of raw pointers this trait is unsafe.
/// Passing an event that has already been waited to OpenC is undefined behavior.
pub unsafe trait WaitlistSizeAndPtr<'a>: Sized {
    /// This function returns a const pointer to a cl_event.
    ///
    /// # Safety
    /// Due to thisfunction involving the use of raw pointers this trait is unsafe.
    /// Passing an event that has already been waited to OpenC is undefined behavior.
    unsafe fn waitlist_len(&self) -> u32;
    unsafe fn waitlist_ptr(&self) -> *const cl_event;

}

unsafe impl<'a> WaitlistSizeAndPtr<'a> for &'a [cl_event] {
    unsafe fn waitlist_len(&self) -> u32 {
        self.len().try_into().unwrap()
    }

    unsafe fn waitlist_ptr(&self) -> *const cl_event {
        match self.len() {
            0 => std::ptr::null() as *const cl_event,
            _ => *self as *const _ as *const cl_event,
        }
    }
}

unsafe impl Waitlist for &[cl_event] {
    unsafe fn fill_waitlist(&self, wait_list: &mut Vec<cl_event>) {
        wait_list.extend_from_slice(self);
    }

    unsafe fn new_waitlist(&self) -> Vec<cl_event> {
        self.to_vec()
    }
}

unsafe impl Waitlist for &[ClEvent] {
    unsafe fn fill_waitlist(&self, wait_list: &mut Vec<cl_event>) {
        let waitlist = self.new_waitlist();
        wait_list.extend(waitlist);
    }

    unsafe fn new_waitlist(&self) -> Vec<cl_event> {
        self.iter().map(|evt| evt.event_ptr()).collect()
    }
}

unsafe impl Waitlist for &ClEvent {
    unsafe fn fill_waitlist(&self, wait_list: &mut Vec<cl_event>) {
        wait_list.push(self.event_ptr());
    }

    unsafe fn new_waitlist(&self) -> Vec<cl_event> {
        vec![self.event_ptr()]
    }
}

unsafe impl<W: Waitlist> Waitlist for Option<W> {
    unsafe fn fill_waitlist(&self, wait_list: &mut Vec<cl_event>) {
        match self {
            None => (),
            Some(event) => event.fill_waitlist(wait_list),
        }
    }

    unsafe fn new_waitlist(&self) -> Vec<cl_event> {
        match self {
            None => vec![],
            Some(event) => event.new_waitlist(),
        }
    }
}