use std::{marker::PhantomData, ptr};
use cugraph_sys::{cugraph_error_t, cugraph_rng_state_create, cugraph_rng_state_t};
use crate::{
cuda::{DeviceResourceKind, drop_device_resource},
error::{Result, check_error, require_non_null},
handle::{EnteredContext, ResourceHandleLease},
};
pub struct RngState {
raw: *mut cugraph_rng_state_t,
device: i32,
_resource_handle_lease: Option<ResourceHandleLease>,
_nosend_nosync: PhantomData<*mut ()>,
}
impl std::fmt::Debug for RngState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RngState").finish_non_exhaustive()
}
}
impl RngState {
pub fn new(handle: &EnteredContext<'_>, seed: u64) -> Result<Self> {
let mut raw: *mut cugraph_rng_state_t = ptr::null_mut();
let mut error: *mut cugraph_error_t = ptr::null_mut();
unsafe {
let code = cugraph_rng_state_create(handle.handle_ptr(), seed, &mut raw, &mut error);
check_error(code, error, handle.device(), "RngState::new")?;
}
let raw = require_non_null(raw, "RngState::new", "rng_state")?;
Ok(Self {
raw,
device: handle.device(),
_resource_handle_lease: handle.runtime_bound_lease(),
_nosend_nosync: PhantomData,
})
}
pub(crate) fn as_ptr(&mut self) -> *mut cugraph_rng_state_t {
self.raw
}
}
impl Drop for RngState {
fn drop(&mut self) {
drop_device_resource(&mut self.raw, self.device, "RngState::drop", DeviceResourceKind::RngState);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ResourceHandle;
#[test]
fn runtime_bound_rng_state_retains_native_owner_until_drop() {
let runtime = std::sync::Arc::new(cudf::Runtime::builder().build().expect("runtime"));
let handle = ResourceHandle::for_runtime(runtime).expect("runtime-bound handle");
let rng = {
let entered = handle.enter("runtime_bound_rng_state_retains_native_owner_until_drop").expect("entered");
RngState::new(&entered, 42).expect("rng state")
};
drop(handle);
let lease = rng._resource_handle_lease.as_ref().expect("runtime-bound rng should retain its native owner");
let mut entered_after_handle_drop = false;
lease.with_teardown_gate(|| entered_after_handle_drop = true);
assert!(entered_after_handle_drop, "the RNG lease must keep the native owner live after its handle drops");
drop(rng);
}
}