async_cuda_core/ffi/
ptr.rs

1/// Represents a device-local pointer. Pointers qualify as device-local if they refer to memory that
2/// lives on the device, and not on the host.
3///
4/// # Safety
5///
6/// ## Null
7///
8/// Creating a null pointer is always unsafe, because any CUDA operations on null pointers can cause
9/// undefined behavior.
10///
11/// Use the `unsafe` function `Ptr::null` to create a null pointer in cases where usage is safe.
12pub struct DevicePtr(*mut std::ffi::c_void);
13
14impl DevicePtr {
15    /// Create from raw pointer.
16    #[inline]
17    pub fn from_raw(raw: *mut std::ffi::c_void) -> Self {
18        if !raw.is_null() {
19            DevicePtr(raw)
20        } else {
21            panic!("unexpected null pointer");
22        }
23    }
24
25    /// Create null pointer.
26    ///
27    /// # Safety
28    ///
29    /// This is unsafe because operating on a `null` pointer in CUDA code can cause crashes. In some
30    /// cases it is allowed though, for example, a `null` pointer can designate the default stream
31    /// in stream-related operations.
32    #[inline]
33    pub unsafe fn null() -> Self {
34        DevicePtr(std::ptr::null_mut())
35    }
36
37    /// Whether or not the device pointer is a null pointer.
38    #[inline]
39    pub fn is_null(&self) -> bool {
40        self.0.is_null()
41    }
42
43    /// Get the readonly pointer value.
44    #[inline(always)]
45    pub fn as_ptr(&self) -> *const std::ffi::c_void {
46        let DevicePtr(ptr) = *self;
47        ptr as *const std::ffi::c_void
48    }
49
50    /// Get the mutable pointer value.
51    #[inline(always)]
52    pub fn as_mut_ptr(&mut self) -> *mut std::ffi::c_void {
53        let DevicePtr(ptr) = *self;
54        ptr
55    }
56
57    /// Take the pointer from this wrapper and replace it with a null pointer.
58    ///
59    /// # Safety
60    ///
61    /// This operation is unsafe because it creates a null pointer.
62    ///
63    /// # Usage
64    ///
65    /// This function can be used inside [`Drop`] if it known that the pointer object will not be
66    /// used for the remainder of the function scope, and the object is to be dropped.
67    ///
68    /// # Example
69    ///
70    /// ```ignore
71    /// # use async_cuda_core::ffi::DevicePtr;
72    /// pub struct Object {
73    ///     internal: DevicePtr,
74    /// }
75    ///
76    /// impl Drop for Object {
77    ///
78    ///     fn drop(&mut self) {
79    ///         // SAFETY: This is safe because `self` and `self.internal`
80    ///         // are not used beyond this unsafe block.
81    ///         let ptr = unsafe {
82    ///             self.internal.take_raw();
83    ///         };
84    ///         // Propertly deallocate the pointer here and do *NOT* use
85    ///         // use `self` for anything!
86    ///     }
87    ///
88    /// }
89    /// ```
90    #[inline]
91    pub unsafe fn take(&mut self) -> DevicePtr {
92        DevicePtr(std::mem::replace(&mut self.0, std::ptr::null_mut()))
93    }
94}
95
96impl From<*mut std::ffi::c_void> for DevicePtr {
97    fn from(value: *mut std::ffi::c_void) -> Self {
98        DevicePtr(value)
99    }
100}
101
102impl std::fmt::Display for DevicePtr {
103    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
104        write!(f, "{:?}", self.0)
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_it_holds_on() {
114        let fake = 0xffffffff as *mut std::ffi::c_void;
115        let ptr = DevicePtr::from_raw(fake);
116        assert_eq!(ptr.as_ptr(), 0xffffffff as *const std::ffi::c_void);
117    }
118
119    #[test]
120    #[should_panic]
121    fn test_it_panics_when_null() {
122        let _ = DevicePtr::from_raw(std::ptr::null_mut());
123    }
124
125    #[test]
126    fn test_null() {
127        let ptr = unsafe { DevicePtr::null() };
128        assert!(ptr.is_null());
129        assert_eq!(ptr.as_ptr(), std::ptr::null_mut());
130    }
131
132    #[test]
133    fn test_take_raw() {
134        let fake = 0xffffffff as *mut std::ffi::c_void;
135        let mut ptr = DevicePtr::from_raw(fake);
136        assert_eq!(
137            unsafe { ptr.take().as_ptr() },
138            0xffffffff as *const std::ffi::c_void,
139        );
140    }
141}