1use std::{marker::PhantomData, ptr};
4
5use cugraph_sys::{
6 cugraph_error_t, cugraph_triangle_count, cugraph_triangle_count_result_get_counts,
7 cugraph_triangle_count_result_get_vertices, cugraph_triangle_count_result_t,
8 cugraph_type_erased_device_array_view_t,
9};
10
11use crate::{
12 array::{DeviceArrayView, RawDeviceArrayView},
13 cuda::{DeviceResourceKind, drop_device_resource},
14 cudf_interop::triangle_count_result_to_dataframe,
15 error::{Error, Result, check_error, require_non_null},
16 graph::Graph,
17 handle::{EnteredContext, ResourceHandleLease},
18 structure::typed_results::{IntegerValues, VertexIds},
19 types::{CugraphElement, to_bool_t},
20};
21
22#[derive(Debug, Clone, Copy, Default)]
24#[must_use]
25pub struct TriangleCountParams {
26 pub do_expensive_check: bool,
28}
29
30pub(crate) fn triangle_count<T, V: CugraphElement>(
35 handle: &EnteredContext<'_>,
36 graph: &mut Graph<T>,
37 start: Option<&DeviceArrayView<'_, V>>,
38 params: &TriangleCountParams,
39) -> Result<TriangleCountResult> {
40 let mut result: *mut cugraph_triangle_count_result_t = ptr::null_mut();
41 let mut error: *mut cugraph_error_t = ptr::null_mut();
42 let start_ptr = start.map(|v| v.as_ptr().cast_const()).unwrap_or(ptr::null());
43 let graph_ptr = graph.as_ptr(handle, "triangle_count")?;
44
45 unsafe {
48 let code = cugraph_triangle_count(
49 handle.handle_ptr(),
50 graph_ptr,
51 start_ptr,
52 to_bool_t(params.do_expensive_check),
53 &mut result,
54 &mut error,
55 );
56 check_error(code, error, handle.device(), "triangle_count")?;
57 }
58
59 let result = require_non_null(result, "triangle_count", "triangle_count_result")?;
60
61 unsafe { TriangleCountResult::from_raw(result, handle.device(), handle.runtime_bound_lease()) }
63}
64
65pub struct TriangleCountResult {
70 raw: *mut cugraph_triangle_count_result_t,
71 device: i32,
72 _resource_handle_lease: Option<ResourceHandleLease>,
74 _nosend_nosync: PhantomData<*mut ()>,
75}
76
77impl std::fmt::Debug for TriangleCountResult {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_struct("TriangleCountResult").finish_non_exhaustive()
80 }
81}
82
83impl TriangleCountResult {
84 pub(crate) unsafe fn from_raw(
91 raw: *mut cugraph_triangle_count_result_t,
92 device: i32,
93 resource_handle_lease: Option<ResourceHandleLease>,
94 ) -> Result<Self> {
95 let raw = require_non_null(raw, "TriangleCountResult::from_raw", "triangle_count_result")?;
96 Ok(Self { raw, device, _resource_handle_lease: resource_handle_lease, _nosend_nosync: PhantomData })
97 }
98
99 fn raw_view(
100 &self,
101 getter: unsafe extern "C" fn(
102 *mut cugraph_triangle_count_result_t,
103 ) -> *mut cugraph_type_erased_device_array_view_t,
104 operation: &'static str,
105 pointer_name: &'static str,
106 ) -> Result<RawDeviceArrayView<'_>> {
107 let view_ptr = require_non_null(
108 unsafe { getter(self.raw) },
110 operation,
111 pointer_name,
112 )?;
113 unsafe { RawDeviceArrayView::from_owned_view(view_ptr, Some(self.device), operation, pointer_name) }
115 }
116
117 pub fn vertex_ids(&self) -> Result<VertexIds<'_>> {
119 VertexIds::from_raw(self.raw_view(
120 cugraph_triangle_count_result_get_vertices,
121 "TriangleCountResult::vertex_ids",
122 "vertices",
123 )?)
124 }
125
126 pub fn counts(&self) -> Result<IntegerValues<'_>> {
128 IntegerValues::from_raw(self.raw_view(
129 cugraph_triangle_count_result_get_counts,
130 "TriangleCountResult::counts",
131 "counts",
132 )?)
133 }
134
135 pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
138 triangle_count_result_to_dataframe(self, runtime)
139 .map_err(|e: Error| e.with_operation("TriangleCountResult::to_dataframe"))
140 }
141}
142
143impl Drop for TriangleCountResult {
144 fn drop(&mut self) {
145 drop_device_resource(
146 &mut self.raw,
147 self.device,
148 "TriangleCountResult::drop",
149 DeviceResourceKind::TriangleCountResult,
150 );
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use std::ptr;
157
158 use super::*;
159 use crate::error::ErrorKind;
160
161 #[test]
162 fn triangle_count_result_from_raw_rejects_null() {
163 let err = match unsafe { TriangleCountResult::from_raw(ptr::null_mut(), 0, None) } {
165 Err(err) => err,
166 Ok(_) => panic!("null must be rejected"),
167 };
168 assert_eq!(err.kind(), ErrorKind::Unexpected);
169 assert_eq!(err.operation(), "TriangleCountResult::from_raw");
170 }
171}