1use crate::{
8 array::{DeviceArrayView, RawDeviceArrayView},
9 error::{Error, ErrorKind, Result},
10 handle::EnteredContext,
11 types::DataType,
12};
13
14pub(super) fn widen_values<T: Into<U>, U>(values: Vec<T>) -> Vec<U> {
15 values.into_iter().map(Into::into).collect()
16}
17
18#[derive(Debug)]
29pub enum VertexIds<'a> {
30 I32(DeviceArrayView<'a, i32>),
32 I64(DeviceArrayView<'a, i64>),
34}
35
36#[derive(Debug)]
45pub enum IntegerValues<'a> {
46 I32(DeviceArrayView<'a, i32>),
48 I64(DeviceArrayView<'a, i64>),
50}
51
52impl<'a> IntegerValues<'a> {
53 pub(crate) fn from_raw(raw: RawDeviceArrayView<'a>) -> Result<Self> {
57 match raw.dtype()? {
58 DataType::Int32 => Ok(Self::I32(DeviceArrayView::from_raw_unchecked(raw))),
59 DataType::Int64 => Ok(Self::I64(DeviceArrayView::from_raw_unchecked(raw))),
60 other => Err(Error::new(ErrorKind::InvalidState, "IntegerValues::from_raw")
61 .with_message(format!("unexpected integer value dtype: {other}"))),
62 }
63 }
64
65 pub fn len(&self) -> usize {
67 match self {
68 Self::I32(v) => v.len(),
69 Self::I64(v) => v.len(),
70 }
71 }
72
73 pub fn is_empty(&self) -> bool {
75 self.len() == 0
76 }
77
78 pub fn to_vec_i64(&self, handle: &EnteredContext<'_>) -> Result<Vec<i64>> {
80 match self {
81 Self::I32(v) => v.to_vec(handle).map(widen_values),
82 Self::I64(v) => v.to_vec(handle),
83 }
84 }
85
86 pub fn to_vec_i32(&self, handle: &EnteredContext<'_>) -> Result<Vec<i32>> {
91 match self {
92 Self::I32(v) => v.to_vec(handle),
93 Self::I64(_) => Err(Error::new(ErrorKind::InvalidState, "IntegerValues::to_vec_i32")
94 .with_message("integer values are i64; use to_vec_i64() to avoid data loss")),
95 }
96 }
97
98 pub fn as_i32(&self) -> Option<&DeviceArrayView<'a, i32>> {
100 match self {
101 Self::I32(v) => Some(v),
102 Self::I64(_) => None,
103 }
104 }
105
106 pub fn as_i64(&self) -> Option<&DeviceArrayView<'a, i64>> {
108 match self {
109 Self::I32(_) => None,
110 Self::I64(v) => Some(v),
111 }
112 }
113}
114
115impl<'a> VertexIds<'a> {
116 pub(crate) fn from_raw(raw: RawDeviceArrayView<'a>) -> Result<Self> {
120 match raw.dtype()? {
121 DataType::Int32 => Ok(Self::I32(DeviceArrayView::from_raw_unchecked(raw))),
122 DataType::Int64 => Ok(Self::I64(DeviceArrayView::from_raw_unchecked(raw))),
123 other => Err(Error::new(ErrorKind::InvalidState, "VertexIds::from_raw")
124 .with_message(format!("unexpected vertex id dtype: {other}"))),
125 }
126 }
127
128 pub fn len(&self) -> usize {
130 match self {
131 Self::I32(v) => v.len(),
132 Self::I64(v) => v.len(),
133 }
134 }
135
136 pub fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140
141 pub fn to_vec_i64(&self, handle: &EnteredContext<'_>) -> Result<Vec<i64>> {
143 match self {
144 Self::I32(v) => v.to_vec(handle).map(widen_values),
145 Self::I64(v) => v.to_vec(handle),
146 }
147 }
148
149 pub fn to_vec_i32(&self, handle: &EnteredContext<'_>) -> Result<Vec<i32>> {
154 match self {
155 Self::I32(v) => v.to_vec(handle),
156 Self::I64(_) => Err(Error::new(ErrorKind::InvalidState, "VertexIds::to_vec_i32")
157 .with_message("vertex ids are i64; use to_vec_i64() to avoid data loss")),
158 }
159 }
160
161 pub fn as_i32(&self) -> Option<&DeviceArrayView<'a, i32>> {
163 match self {
164 Self::I32(v) => Some(v),
165 Self::I64(_) => None,
166 }
167 }
168
169 pub fn as_i64(&self) -> Option<&DeviceArrayView<'a, i64>> {
171 match self {
172 Self::I32(_) => None,
173 Self::I64(v) => Some(v),
174 }
175 }
176}
177
178#[derive(Debug)]
186pub struct SizeValues<'a>(DeviceArrayView<'a, usize>);
187
188impl<'a> SizeValues<'a> {
189 pub(crate) fn from_raw(raw: RawDeviceArrayView<'a>) -> Result<Self> {
191 match raw.dtype()? {
192 DataType::SizeT => Ok(Self(DeviceArrayView::from_raw_unchecked(raw))),
193 other => Err(Error::new(ErrorKind::InvalidState, "SizeValues::from_raw")
194 .with_message(format!("unexpected size_t value dtype: {other}"))),
195 }
196 }
197
198 pub fn len(&self) -> usize {
200 self.0.len()
201 }
202
203 pub fn is_empty(&self) -> bool {
205 self.0.len() == 0
206 }
207
208 pub fn to_vec_usize(&self, handle: &EnteredContext<'_>) -> Result<Vec<usize>> {
210 self.0.to_vec(handle)
211 }
212
213 pub fn as_usize(&self) -> &DeviceArrayView<'a, usize> {
215 &self.0
216 }
217}
218
219#[derive(Debug)]
230pub enum ScoreValues<'a> {
231 F32(DeviceArrayView<'a, f32>),
233 F64(DeviceArrayView<'a, f64>),
235}
236
237impl<'a> ScoreValues<'a> {
238 pub(crate) fn from_raw(raw: RawDeviceArrayView<'a>) -> Result<Self> {
242 match raw.dtype()? {
243 DataType::Float32 => Ok(Self::F32(DeviceArrayView::from_raw_unchecked(raw))),
244 DataType::Float64 => Ok(Self::F64(DeviceArrayView::from_raw_unchecked(raw))),
245 other => Err(Error::new(ErrorKind::InvalidState, "ScoreValues::from_raw")
246 .with_message(format!("unexpected score dtype: {other}"))),
247 }
248 }
249
250 pub fn len(&self) -> usize {
252 match self {
253 Self::F32(v) => v.len(),
254 Self::F64(v) => v.len(),
255 }
256 }
257
258 pub fn is_empty(&self) -> bool {
260 self.len() == 0
261 }
262
263 pub fn to_vec_f64(&self, handle: &EnteredContext<'_>) -> Result<Vec<f64>> {
265 match self {
266 Self::F32(v) => v.to_vec(handle).map(widen_values),
267 Self::F64(v) => v.to_vec(handle),
268 }
269 }
270
271 pub fn to_vec_f32(&self, handle: &EnteredContext<'_>) -> Result<Vec<f32>> {
276 match self {
277 Self::F32(v) => v.to_vec(handle),
278 Self::F64(_) => Err(Error::new(ErrorKind::InvalidState, "ScoreValues::to_vec_f32")
279 .with_message("score values are f64; use to_vec_f64() to avoid data loss")),
280 }
281 }
282
283 pub fn as_f32(&self) -> Option<&DeviceArrayView<'a, f32>> {
285 match self {
286 Self::F32(v) => Some(v),
287 Self::F64(_) => None,
288 }
289 }
290
291 pub fn as_f64(&self) -> Option<&DeviceArrayView<'a, f64>> {
293 match self {
294 Self::F32(_) => None,
295 Self::F64(v) => Some(v),
296 }
297 }
298}
299
300#[derive(Debug)]
314pub enum Distances<'a> {
315 I32(DeviceArrayView<'a, i32>),
317 I64(DeviceArrayView<'a, i64>),
319 F32(DeviceArrayView<'a, f32>),
321 F64(DeviceArrayView<'a, f64>),
323}
324
325impl<'a> Distances<'a> {
326 pub(crate) fn from_raw(raw: RawDeviceArrayView<'a>) -> Result<Self> {
330 match raw.dtype()? {
331 DataType::Int32 => Ok(Self::I32(DeviceArrayView::from_raw_unchecked(raw))),
332 DataType::Int64 => Ok(Self::I64(DeviceArrayView::from_raw_unchecked(raw))),
333 DataType::Float32 => Ok(Self::F32(DeviceArrayView::from_raw_unchecked(raw))),
334 DataType::Float64 => Ok(Self::F64(DeviceArrayView::from_raw_unchecked(raw))),
335 other => Err(Error::new(ErrorKind::InvalidState, "Distances::from_raw")
336 .with_message(format!("unexpected distance dtype: {other}"))),
337 }
338 }
339
340 pub fn len(&self) -> usize {
342 match self {
343 Self::I32(v) => v.len(),
344 Self::I64(v) => v.len(),
345 Self::F32(v) => v.len(),
346 Self::F64(v) => v.len(),
347 }
348 }
349
350 pub fn is_empty(&self) -> bool {
352 self.len() == 0
353 }
354
355 pub fn to_vec_i64(&self, handle: &EnteredContext<'_>) -> Result<Vec<i64>> {
360 match self {
361 Self::I32(v) => v.to_vec(handle).map(widen_values),
362 Self::I64(v) => v.to_vec(handle),
363 Self::F32(_) | Self::F64(_) => Err(Error::new(ErrorKind::InvalidState, "Distances::to_vec_i64")
364 .with_message("distances are floating-point; use to_vec_f64()")),
365 }
366 }
367
368 pub fn to_vec_i32(&self, handle: &EnteredContext<'_>) -> Result<Vec<i32>> {
373 match self {
374 Self::I32(v) => v.to_vec(handle),
375 Self::I64(_) => Err(Error::new(ErrorKind::InvalidState, "Distances::to_vec_i32")
376 .with_message("distances are i64; use to_vec_i64() to avoid data loss")),
377 Self::F32(_) | Self::F64(_) => Err(Error::new(ErrorKind::InvalidState, "Distances::to_vec_i32")
378 .with_message("distances are floating-point; use to_vec_f64()")),
379 }
380 }
381
382 pub fn to_vec_f64(&self, handle: &EnteredContext<'_>) -> Result<Vec<f64>> {
387 match self {
388 Self::I32(v) => v.to_vec(handle).map(widen_values),
389 Self::I64(v) => {
390 let vals = v.to_vec(handle)?;
391 Ok(vals.into_iter().map(|x| x as f64).collect())
392 },
393 Self::F32(v) => v.to_vec(handle).map(widen_values),
394 Self::F64(v) => v.to_vec(handle),
395 }
396 }
397
398 pub fn to_vec_f32(&self, handle: &EnteredContext<'_>) -> Result<Vec<f32>> {
403 match self {
404 Self::F32(v) => v.to_vec(handle),
405 _ => Err(Error::new(ErrorKind::InvalidState, "Distances::to_vec_f32")
406 .with_message("distances are not f32; use to_vec_f64() for a lossless conversion")),
407 }
408 }
409}
410
411#[cfg(test)]
412mod tests {
413 use cudf::testing::run_named_cases;
414
415 use super::*;
416 use crate::{
417 ResourceHandle,
418 array::{DeviceArray, RawDeviceArrayView},
419 error::ErrorKind,
420 structure::DegreeValues,
421 types::DataType,
422 };
423
424 #[test]
425 fn native_owner_cases_1() {
426 run_named_cases(&[
427 (
428 "structure::typed_results::tests::vertex_ids_i64_to_vec_i32_is_invalid_state",
429 vertex_ids_i64_to_vec_i32_is_invalid_state,
430 ),
431 (
432 "structure::typed_results::tests::score_values_f64_to_vec_f32_is_invalid_state",
433 score_values_f64_to_vec_f32_is_invalid_state,
434 ),
435 (
436 "structure::typed_results::tests::distances_float_to_vec_i64_is_invalid_state",
437 distances_float_to_vec_i64_is_invalid_state,
438 ),
439 (
440 "structure::typed_results::tests::distances_i64_to_vec_i32_is_invalid_state",
441 distances_i64_to_vec_i32_is_invalid_state,
442 ),
443 (
444 "structure::typed_results::tests::distances_non_f32_to_vec_f32_is_invalid_state",
445 distances_non_f32_to_vec_f32_is_invalid_state,
446 ),
447 (
448 "structure::typed_results::tests::vertex_ids_from_raw_unexpected_dtype_is_invalid_state",
449 vertex_ids_from_raw_unexpected_dtype_is_invalid_state,
450 ),
451 (
452 "structure::typed_results::tests::score_values_from_raw_unexpected_dtype_is_invalid_state",
453 score_values_from_raw_unexpected_dtype_is_invalid_state,
454 ),
455 (
456 "structure::typed_results::tests::distances_from_raw_unexpected_dtype_is_invalid_state",
457 distances_from_raw_unexpected_dtype_is_invalid_state,
458 ),
459 (
460 "structure::degrees::tests::degree_values_i64_to_vec_i32_is_invalid_state",
461 degree_values_i64_to_vec_i32_is_invalid_state,
462 ),
463 (
464 "structure::degrees::tests::degree_values_from_raw_unexpected_dtype_is_invalid_state",
465 degree_values_from_raw_unexpected_dtype_is_invalid_state,
466 ),
467 ("array::tests::test_from_raw_roundtrip", test_from_raw_roundtrip),
468 ]);
469 }
470
471 fn vertex_ids_i64_to_vec_i32_is_invalid_state() {
472 let handle = ResourceHandle::new().expect("handle");
473 let entered = handle.enter("vertex_ids_i64_to_vec_i32_is_invalid_state").expect("entered");
474 let ids = DeviceArray::from_slice(&entered, &[1i64, 2, 3]).expect("ids");
475 let values = VertexIds::I64(ids.view().expect("view"));
476
477 let err = values.to_vec_i32(&entered).expect_err("i64 vertex ids should reject i32 copy");
478 assert_eq!(err.kind(), ErrorKind::InvalidState);
479 assert_eq!(err.operation(), "VertexIds::to_vec_i32");
480 }
481
482 fn score_values_f64_to_vec_f32_is_invalid_state() {
483 let handle = ResourceHandle::new().expect("handle");
484 let entered = handle.enter("score_values_f64_to_vec_f32_is_invalid_state").expect("entered");
485 let scores = DeviceArray::from_slice(&entered, &[1.0f64, 2.0, 3.0]).expect("scores");
486 let values = ScoreValues::F64(scores.view().expect("view"));
487
488 let err = values.to_vec_f32(&entered).expect_err("f64 score values should reject f32 copy");
489 assert_eq!(err.kind(), ErrorKind::InvalidState);
490 assert_eq!(err.operation(), "ScoreValues::to_vec_f32");
491 }
492
493 fn distances_float_to_vec_i64_is_invalid_state() {
494 let handle = ResourceHandle::new().expect("handle");
495 let entered = handle.enter("distances_float_to_vec_i64_is_invalid_state").expect("entered");
496 let distances = DeviceArray::from_slice(&entered, &[1.5f32, 2.5, 3.5]).expect("distances");
497 let values = Distances::F32(distances.view().expect("view"));
498
499 let err = values.to_vec_i64(&entered).expect_err("float distances should reject integer copy");
500 assert_eq!(err.kind(), ErrorKind::InvalidState);
501 assert_eq!(err.operation(), "Distances::to_vec_i64");
502 }
503
504 fn distances_i64_to_vec_i32_is_invalid_state() {
505 let handle = ResourceHandle::new().expect("handle");
506 let entered = handle.enter("distances_i64_to_vec_i32_is_invalid_state").expect("entered");
507 let distances = DeviceArray::from_slice(&entered, &[10i64, 20, 30]).expect("distances");
508 let values = Distances::I64(distances.view().expect("view"));
509
510 let err = values.to_vec_i32(&entered).expect_err("i64 distances should reject i32 copy");
511 assert_eq!(err.kind(), ErrorKind::InvalidState);
512 assert_eq!(err.operation(), "Distances::to_vec_i32");
513 }
514
515 fn distances_non_f32_to_vec_f32_is_invalid_state() {
516 let handle = ResourceHandle::new().expect("handle");
517 let entered = handle.enter("distances_non_f32_to_vec_f32_is_invalid_state").expect("entered");
518 let distances = DeviceArray::from_slice(&entered, &[10i32, 20, 30]).expect("distances");
519 let values = Distances::I32(distances.view().expect("view"));
520
521 let err = values.to_vec_f32(&entered).expect_err("non-f32 distances should reject f32 copy");
522 assert_eq!(err.kind(), ErrorKind::InvalidState);
523 assert_eq!(err.operation(), "Distances::to_vec_f32");
524 }
525
526 fn vertex_ids_from_raw_unexpected_dtype_is_invalid_state() {
527 let handle = ResourceHandle::new().expect("handle");
528 let entered = handle.enter("vertex_ids_from_raw_unexpected_dtype_is_invalid_state").expect("entered");
529 let ids = DeviceArray::from_slice(&entered, &[1i16, 2, 3]).expect("ids");
530 let view = ids.view().expect("view");
531 let raw = unsafe {
534 RawDeviceArrayView::try_from_raw(view.device_ptr(), view.len(), DataType::Int16, "test_raw")
535 .expect("raw view")
536 };
537
538 let err = VertexIds::from_raw(raw).expect_err("unexpected vertex dtype should be rejected");
539 assert_eq!(err.kind(), ErrorKind::InvalidState);
540 assert_eq!(err.operation(), "VertexIds::from_raw");
541 }
542
543 fn score_values_from_raw_unexpected_dtype_is_invalid_state() {
544 let handle = ResourceHandle::new().expect("handle");
545 let entered = handle.enter("score_values_from_raw_unexpected_dtype_is_invalid_state").expect("entered");
546 let scores = DeviceArray::from_slice(&entered, &[1i32, 2, 3]).expect("scores");
547 let view = scores.view().expect("view");
548 let raw = unsafe {
551 RawDeviceArrayView::try_from_raw(view.device_ptr(), view.len(), DataType::Int32, "test_raw")
552 .expect("raw view")
553 };
554
555 let err = ScoreValues::from_raw(raw).expect_err("unexpected score dtype should be rejected");
556 assert_eq!(err.kind(), ErrorKind::InvalidState);
557 assert_eq!(err.operation(), "ScoreValues::from_raw");
558 }
559
560 fn distances_from_raw_unexpected_dtype_is_invalid_state() {
561 let handle = ResourceHandle::new().expect("handle");
562 let entered = handle.enter("distances_from_raw_unexpected_dtype_is_invalid_state").expect("entered");
563 let distances = DeviceArray::from_slice(&entered, &[1i16, 2, 3]).expect("distances");
564 let view = distances.view().expect("view");
565 let raw = unsafe {
568 RawDeviceArrayView::try_from_raw(view.device_ptr(), view.len(), DataType::Int16, "test_raw")
569 .expect("raw view")
570 };
571
572 let err = Distances::from_raw(raw).expect_err("unexpected distance dtype should be rejected");
573 assert_eq!(err.kind(), ErrorKind::InvalidState);
574 assert_eq!(err.operation(), "Distances::from_raw");
575 }
576
577 fn degree_values_i64_to_vec_i32_is_invalid_state() {
578 let handle = ResourceHandle::new().expect("handle");
579 let entered = handle.enter("degree_values_i64_to_vec_i32_is_invalid_state").expect("entered");
580 let degrees = DeviceArray::from_slice(&entered, &[1i64, 2, 3]).expect("degrees");
581 let values = DegreeValues::I64(degrees.view().expect("view"));
582
583 let err = values.to_vec_i32(&entered).expect_err("i64 degree values should reject i32 copy");
584 assert_eq!(err.kind(), ErrorKind::InvalidState);
585 assert_eq!(err.operation(), "DegreeValues::to_vec_i32");
586 }
587
588 fn degree_values_from_raw_unexpected_dtype_is_invalid_state() {
589 let handle = ResourceHandle::new().expect("handle");
590 let entered = handle.enter("degree_values_from_raw_unexpected_dtype_is_invalid_state").expect("entered");
591 let degrees = DeviceArray::from_slice(&entered, &[1.0f32, 2.0, 3.0]).expect("degrees");
592 let view = degrees.view().expect("view");
593 let raw = unsafe {
596 RawDeviceArrayView::try_from_raw(view.device_ptr(), view.len(), DataType::Float32, "test_raw")
597 .expect("raw view")
598 };
599
600 let err = DegreeValues::from_raw(raw).expect_err("unexpected degree dtype should be rejected");
601 assert_eq!(err.kind(), ErrorKind::InvalidState);
602 assert_eq!(err.operation(), "DegreeValues::from_raw");
603 }
604
605 fn test_from_raw_roundtrip() {
606 let handle = ResourceHandle::new().expect("handle");
607 let entered = handle.enter("test_from_raw_roundtrip").expect("entered");
608 let arr = DeviceArray::from_slice(&entered, &[100i32, 200, 300]).expect("create");
609
610 let owned_view = arr.view().expect("owned_view");
611 let raw_ptr = owned_view.device_ptr();
612
613 let raw_view = unsafe { DeviceArrayView::<i32>::from_raw(raw_ptr, 3) }.expect("raw_view");
616 assert_eq!(raw_view.len(), 3);
617
618 let result: Vec<i32> = raw_view.to_vec(&entered).expect("to_vec");
619 assert_eq!(result, vec![100, 200, 300]);
620 }
621}