1use std::{marker::PhantomData, ptr};
19
20use cugraph_sys::{cugraph_error_t, cugraph_rng_state_create, cugraph_rng_state_t};
21
22use crate::{
23 cuda::{DeviceResourceKind, drop_device_resource},
24 error::{Result, check_error, require_non_null},
25 handle::{EnteredContext, ResourceHandleLease},
26};
27
28pub struct RngState {
34 raw: *mut cugraph_rng_state_t,
35 device: i32,
36 _resource_handle_lease: Option<ResourceHandleLease>,
38 _nosend_nosync: PhantomData<*mut ()>,
39}
40
41impl std::fmt::Debug for RngState {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("RngState").finish_non_exhaustive()
44 }
45}
46
47impl RngState {
48 pub fn new(handle: &EnteredContext<'_>, seed: u64) -> Result<Self> {
53 let mut raw: *mut cugraph_rng_state_t = ptr::null_mut();
54 let mut error: *mut cugraph_error_t = ptr::null_mut();
55
56 unsafe {
59 let code = cugraph_rng_state_create(handle.handle_ptr(), seed, &mut raw, &mut error);
60 check_error(code, error, handle.device(), "RngState::new")?;
61 }
62
63 let raw = require_non_null(raw, "RngState::new", "rng_state")?;
64
65 Ok(Self {
66 raw,
67 device: handle.device(),
68 _resource_handle_lease: handle.runtime_bound_lease(),
69 _nosend_nosync: PhantomData,
70 })
71 }
72
73 pub(crate) fn as_ptr(&mut self) -> *mut cugraph_rng_state_t {
75 self.raw
76 }
77}
78
79impl Drop for RngState {
80 fn drop(&mut self) {
81 drop_device_resource(&mut self.raw, self.device, "RngState::drop", DeviceResourceKind::RngState);
82 }
83}
84
85#[cfg(test)]
86mod tests {
87
88 use super::*;
89 use crate::ResourceHandle;
90
91 #[test]
92 fn runtime_bound_rng_state_retains_native_owner_until_drop() {
93 let runtime = std::sync::Arc::new(cudf::Runtime::builder().build().expect("runtime"));
94 let handle = ResourceHandle::for_runtime(runtime).expect("runtime-bound handle");
95 let rng = {
96 let entered = handle.enter("runtime_bound_rng_state_retains_native_owner_until_drop").expect("entered");
97 RngState::new(&entered, 42).expect("rng state")
98 };
99
100 drop(handle);
101 let lease = rng._resource_handle_lease.as_ref().expect("runtime-bound rng should retain its native owner");
102 let mut entered_after_handle_drop = false;
103 lease.with_teardown_gate(|| entered_after_handle_drop = true);
104 assert!(entered_after_handle_drop, "the RNG lease must keep the native owner live after its handle drops");
105 drop(rng);
106 }
107}