use std::marker::PhantomData;
use cugraph_sys::{
cugraph_centrality_result_converged, cugraph_centrality_result_get_num_iterations,
cugraph_centrality_result_get_values, cugraph_centrality_result_get_vertices, cugraph_centrality_result_t,
cugraph_edge_centrality_result_get_dst_vertices, cugraph_edge_centrality_result_get_edge_ids,
cugraph_edge_centrality_result_get_src_vertices, cugraph_edge_centrality_result_get_values,
cugraph_edge_centrality_result_t, cugraph_hits_result_converged, cugraph_hits_result_get_authorities,
cugraph_hits_result_get_hub_score_differences, cugraph_hits_result_get_hubs,
cugraph_hits_result_get_number_of_iterations, cugraph_hits_result_get_vertices, cugraph_hits_result_t,
};
use crate::{
array::RawDeviceArrayView,
cuda::{DeviceResourceKind, drop_device_resource},
cudf_interop::{
centrality_result_to_dataframe, edge_betweenness_centrality_result_to_dataframe, hits_result_to_dataframe,
},
error::{Error, ErrorKind, Result, require_non_null},
handle::ResourceHandleLease,
structure::typed_results::{IntegerValues, ScoreValues, VertexIds},
types::try_from_bool_t,
};
pub struct CentralityResult {
raw: *mut cugraph_centrality_result_t,
device: i32,
_resource_handle_lease: Option<ResourceHandleLease>,
_nosend_nosync: PhantomData<*mut ()>,
}
impl std::fmt::Debug for CentralityResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CentralityResult").finish_non_exhaustive()
}
}
impl CentralityResult {
pub(crate) unsafe fn from_raw(
raw: *mut cugraph_centrality_result_t,
device: i32,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
let raw = require_non_null(raw, "CentralityResult::from_raw", "centrality_result")?;
Ok(Self { raw, device, _resource_handle_lease: resource_handle_lease, _nosend_nosync: PhantomData })
}
pub(crate) fn vertices_raw(&self) -> Result<RawDeviceArrayView<'_>> {
let view_ptr = require_non_null(
unsafe { cugraph_centrality_result_get_vertices(self.raw) },
"CentralityResult::vertices_raw",
"vertices",
)?;
unsafe {
RawDeviceArrayView::from_owned_view(
view_ptr,
Some(self.device),
"CentralityResult::vertices_raw",
"vertices",
)
}
}
pub(crate) fn values_raw(&self) -> Result<RawDeviceArrayView<'_>> {
let view_ptr = require_non_null(
unsafe { cugraph_centrality_result_get_values(self.raw) },
"CentralityResult::values_raw",
"values",
)?;
unsafe {
RawDeviceArrayView::from_owned_view(view_ptr, Some(self.device), "CentralityResult::values_raw", "values")
}
}
pub fn vertex_ids(&self) -> Result<VertexIds<'_>> {
VertexIds::from_raw(self.vertices_raw()?)
}
pub fn scores(&self) -> Result<ScoreValues<'_>> {
ScoreValues::from_raw(self.values_raw()?)
}
pub fn num_iterations(&self) -> usize {
unsafe { cugraph_centrality_result_get_num_iterations(self.raw) }
}
pub fn converged(&self) -> Result<bool> {
let b = unsafe { cugraph_centrality_result_converged(self.raw) };
try_from_bool_t(b).ok_or_else(|| {
Error::new(ErrorKind::Unexpected, "CentralityResult::converged")
.with_message(format!("invalid bool_t value returned by cuGraph: {}", b.0))
})
}
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
centrality_result_to_dataframe(self, runtime)
.map_err(|e: Error| e.with_operation("CentralityResult::to_dataframe"))
}
}
impl Drop for CentralityResult {
fn drop(&mut self) {
drop_device_resource(
&mut self.raw,
self.device,
"CentralityResult::drop",
DeviceResourceKind::CentralityResult,
);
}
}
pub struct BetweennessCentralityResult(CentralityResult);
impl std::fmt::Debug for BetweennessCentralityResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BetweennessCentralityResult").finish_non_exhaustive()
}
}
pub(crate) struct EdgeCentralityResult {
raw: *mut cugraph_edge_centrality_result_t,
device: i32,
has_edge_ids: bool,
_resource_handle_lease: Option<ResourceHandleLease>,
_nosend_nosync: PhantomData<*mut ()>,
}
impl EdgeCentralityResult {
pub(crate) unsafe fn from_raw(
raw: *mut cugraph_edge_centrality_result_t,
device: i32,
has_edge_ids: bool,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
let raw = require_non_null(raw, "EdgeCentralityResult::from_raw", "edge_centrality_result")?;
Ok(Self {
raw,
device,
has_edge_ids,
_resource_handle_lease: resource_handle_lease,
_nosend_nosync: PhantomData,
})
}
fn raw_view(
&self,
getter: unsafe extern "C" fn(
*mut cugraph_edge_centrality_result_t,
) -> *mut cugraph_sys::cugraph_type_erased_device_array_view_t,
operation: &'static str,
pointer_name: &'static str,
) -> Result<RawDeviceArrayView<'_>> {
let view_ptr = require_non_null(
unsafe { getter(self.raw) },
operation,
pointer_name,
)?;
unsafe { RawDeviceArrayView::from_owned_view(view_ptr, Some(self.device), operation, pointer_name) }
}
pub(crate) fn sources(&self, operation: &'static str) -> Result<VertexIds<'_>> {
VertexIds::from_raw(self.raw_view(cugraph_edge_centrality_result_get_src_vertices, operation, "sources")?)
}
pub(crate) fn destinations(&self, operation: &'static str) -> Result<VertexIds<'_>> {
VertexIds::from_raw(self.raw_view(
cugraph_edge_centrality_result_get_dst_vertices,
operation,
"destinations",
)?)
}
pub(crate) fn values(&self, operation: &'static str) -> Result<ScoreValues<'_>> {
ScoreValues::from_raw(self.raw_view(cugraph_edge_centrality_result_get_values, operation, "values")?)
}
pub(crate) fn edge_ids(&self, operation: &'static str) -> Result<Option<IntegerValues<'_>>> {
if !self.has_edge_ids {
return Ok(None);
}
IntegerValues::from_raw(self.raw_view(cugraph_edge_centrality_result_get_edge_ids, operation, "edge_ids")?)
.map(Some)
}
}
impl Drop for EdgeCentralityResult {
fn drop(&mut self) {
drop_device_resource(
&mut self.raw,
self.device,
"EdgeCentralityResult::drop",
DeviceResourceKind::EdgeCentralityResult,
);
}
}
pub struct EdgeBetweennessCentralityResult(EdgeCentralityResult);
impl std::fmt::Debug for EdgeBetweennessCentralityResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EdgeBetweennessCentralityResult").finish_non_exhaustive()
}
}
impl EdgeBetweennessCentralityResult {
pub(crate) unsafe fn from_raw(
raw: *mut cugraph_edge_centrality_result_t,
device: i32,
has_edge_ids: bool,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
Ok(Self(unsafe { EdgeCentralityResult::from_raw(raw, device, has_edge_ids, resource_handle_lease) }?))
}
pub fn sources(&self) -> Result<VertexIds<'_>> {
self.0.sources("EdgeBetweennessCentralityResult::sources")
}
pub fn destinations(&self) -> Result<VertexIds<'_>> {
self.0.destinations("EdgeBetweennessCentralityResult::destinations")
}
pub fn edge_ids(&self) -> Result<Option<IntegerValues<'_>>> {
self.0.edge_ids("EdgeBetweennessCentralityResult::edge_ids")
}
pub fn scores(&self) -> Result<ScoreValues<'_>> {
self.0.values("EdgeBetweennessCentralityResult::scores")
}
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
edge_betweenness_centrality_result_to_dataframe(self, runtime)
.map_err(|e: Error| e.with_operation("EdgeBetweennessCentralityResult::to_dataframe"))
}
}
pub struct HitsResult {
raw: *mut cugraph_hits_result_t,
device: i32,
_resource_handle_lease: Option<ResourceHandleLease>,
_nosend_nosync: PhantomData<*mut ()>,
}
impl std::fmt::Debug for HitsResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HitsResult").finish_non_exhaustive()
}
}
impl HitsResult {
pub(crate) unsafe fn from_raw(
raw: *mut cugraph_hits_result_t,
device: i32,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
let raw = require_non_null(raw, "HitsResult::from_raw", "hits_result")?;
Ok(Self { raw, device, _resource_handle_lease: resource_handle_lease, _nosend_nosync: PhantomData })
}
fn raw_view(
&self,
getter: unsafe extern "C" fn(
*mut cugraph_hits_result_t,
) -> *mut cugraph_sys::cugraph_type_erased_device_array_view_t,
operation: &'static str,
pointer_name: &'static str,
) -> Result<RawDeviceArrayView<'_>> {
let view_ptr = require_non_null(
unsafe { getter(self.raw) },
operation,
pointer_name,
)?;
unsafe { RawDeviceArrayView::from_owned_view(view_ptr, Some(self.device), operation, pointer_name) }
}
pub fn vertex_ids(&self) -> Result<VertexIds<'_>> {
VertexIds::from_raw(self.raw_view(cugraph_hits_result_get_vertices, "HitsResult::vertex_ids", "vertices")?)
}
pub fn hub_scores(&self) -> Result<ScoreValues<'_>> {
ScoreValues::from_raw(self.raw_view(cugraph_hits_result_get_hubs, "HitsResult::hub_scores", "hubs")?)
}
pub fn authority_scores(&self) -> Result<ScoreValues<'_>> {
ScoreValues::from_raw(self.raw_view(
cugraph_hits_result_get_authorities,
"HitsResult::authority_scores",
"authorities",
)?)
}
pub fn hub_score_differences(&self) -> f64 {
unsafe { cugraph_hits_result_get_hub_score_differences(self.raw) }
}
pub fn number_of_iterations(&self) -> usize {
unsafe { cugraph_hits_result_get_number_of_iterations(self.raw) }
}
pub fn converged(&self) -> Result<bool> {
let b = unsafe { cugraph_hits_result_converged(self.raw) };
try_from_bool_t(b).ok_or_else(|| {
Error::new(ErrorKind::Unexpected, "HitsResult::converged")
.with_message(format!("invalid bool_t value returned by cuGraph: {}", b.0))
})
}
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
hits_result_to_dataframe(self, runtime).map_err(|e: Error| e.with_operation("HitsResult::to_dataframe"))
}
}
impl Drop for HitsResult {
fn drop(&mut self) {
drop_device_resource(&mut self.raw, self.device, "HitsResult::drop", DeviceResourceKind::HitsResult);
}
}
impl BetweennessCentralityResult {
pub(crate) unsafe fn from_raw(
raw: *mut cugraph_centrality_result_t,
device: i32,
resource_handle_lease: Option<ResourceHandleLease>,
) -> Result<Self> {
Ok(Self(unsafe { CentralityResult::from_raw(raw, device, resource_handle_lease) }?))
}
pub fn vertex_ids(&self) -> Result<VertexIds<'_>> {
self.0.vertex_ids()
}
pub fn scores(&self) -> Result<ScoreValues<'_>> {
self.0.scores()
}
}
impl BetweennessCentralityResult {
pub fn to_dataframe(&self, runtime: &cudf::Runtime) -> Result<cudf::DataFrame> {
centrality_result_to_dataframe(&self.0, runtime)
.map_err(|e: Error| e.with_operation("BetweennessCentralityResult::to_dataframe"))
}
}
#[cfg(test)]
mod tests {
use std::ptr;
use super::*;
#[test]
fn centrality_result_from_raw_rejects_null() {
let err = match unsafe { CentralityResult::from_raw(ptr::null_mut(), 0, None) } {
Err(err) => err,
Ok(_) => panic!("null must be rejected"),
};
assert_eq!(err.kind(), ErrorKind::Unexpected);
assert_eq!(err.operation(), "CentralityResult::from_raw");
}
#[test]
fn edge_centrality_result_from_raw_rejects_null() {
let err = match unsafe { EdgeCentralityResult::from_raw(ptr::null_mut(), 0, false, None) } {
Err(err) => err,
Ok(_) => panic!("null must be rejected"),
};
assert_eq!(err.kind(), ErrorKind::Unexpected);
assert_eq!(err.operation(), "EdgeCentralityResult::from_raw");
}
#[test]
fn hits_result_from_raw_rejects_null() {
let err = match unsafe { HitsResult::from_raw(ptr::null_mut(), 0, None) } {
Err(err) => err,
Ok(_) => panic!("null must be rejected"),
};
assert_eq!(err.kind(), ErrorKind::Unexpected);
assert_eq!(err.operation(), "HitsResult::from_raw");
}
}