spatialrust_arrow/
device.rs1use std::ptr;
4
5use spatialrust_core::{PointCloud, SpatialMetadata};
6
7use crate::{
8 cdata::{
9 export_point_cloud_c_data, import_point_cloud_c_data, ArrowArray, ExportedArrowSchema,
10 },
11 ArrowBridgeError, ArrowBridgeResult,
12};
13
14#[repr(i32)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17pub enum ArrowDeviceType {
18 Cpu = 1,
20 Cuda = 2,
22}
23
24#[repr(C)]
26pub struct ArrowDeviceArray {
27 pub array: ArrowArray,
29 pub device_id: i64,
31 pub device_type: i32,
33 pub sync_event: *mut std::ffi::c_void,
35 pub reserved: [i64; 3],
37}
38
39pub struct ExportedArrowDeviceArray {
41 schema: ExportedArrowSchema,
42 device: Box<ArrowDeviceArray>,
43}
44
45impl ExportedArrowDeviceArray {
46 #[must_use]
48 pub fn schema(&mut self) -> &mut ExportedArrowSchema {
49 &mut self.schema
50 }
51
52 pub fn as_mut_ptr(&mut self) -> *mut ArrowDeviceArray {
54 self.device.as_mut()
55 }
56}
57
58impl Drop for ExportedArrowDeviceArray {
59 fn drop(&mut self) {
60 if let Some(release) = self.device.array.release {
61 unsafe { release(&mut self.device.array) };
62 self.device.array.release = None;
63 }
64 }
65}
66
67pub fn export_point_cloud_device_array(
69 cloud: &PointCloud,
70) -> ArrowBridgeResult<ExportedArrowDeviceArray> {
71 let (schema, mut array) = export_point_cloud_c_data(cloud)?;
72 let moved = unsafe { ptr::read(array.as_mut_ptr()) };
73 unsafe {
74 (*array.as_mut_ptr()).release = None;
75 (*array.as_mut_ptr()).private_data = ptr::null_mut();
76 (*array.as_mut_ptr()).buffers = ptr::null_mut();
77 (*array.as_mut_ptr()).children = ptr::null_mut();
78 }
79 drop(array);
80 let device = Box::new(ArrowDeviceArray {
81 array: moved,
82 device_id: -1,
83 device_type: ArrowDeviceType::Cpu as i32,
84 sync_event: ptr::null_mut(),
85 reserved: [0; 3],
86 });
87 Ok(ExportedArrowDeviceArray { schema, device })
88}
89
90pub unsafe fn import_point_cloud_device_array(
98 schema: *const crate::cdata::ArrowSchema,
99 device_array: *const ArrowDeviceArray,
100 metadata: SpatialMetadata,
101) -> ArrowBridgeResult<PointCloud> {
102 if device_array.is_null() {
103 return Err(ArrowBridgeError::NullPointer("device array".into()));
104 }
105 let device_array = &*device_array;
106 if device_array.device_type != ArrowDeviceType::Cpu as i32 {
107 return Err(ArrowBridgeError::InvalidConfiguration(format!(
108 "Arrow device type {} is not supported without an explicit device copy",
109 device_array.device_type
110 )));
111 }
112 import_point_cloud_c_data(schema, &device_array.array, metadata)
113}
114
115#[cfg(test)]
116mod tests {
117 use super::{
118 export_point_cloud_device_array, import_point_cloud_device_array, ArrowDeviceType,
119 };
120 use spatialrust_core::{
121 PointBuffer, PointBufferSet, PointCloud, SpatialMetadata, StandardSchemas,
122 };
123
124 #[test]
125 fn cpu_device_array_roundtrip() {
126 let mut buffers = PointBufferSet::new();
127 buffers.insert("x", PointBuffer::from_f32(vec![1.0]));
128 buffers.insert("y", PointBuffer::from_f32(vec![2.0]));
129 buffers.insert("z", PointBuffer::from_f32(vec![3.0]));
130 let cloud = PointCloud::try_from_parts(
131 StandardSchemas::point_xyz(),
132 buffers,
133 SpatialMetadata::default(),
134 )
135 .unwrap();
136 let mut exported = export_point_cloud_device_array(&cloud).unwrap();
137 let schema_ptr = exported.schema().as_mut_ptr();
138 let device_ptr = exported.as_mut_ptr();
139 assert_eq!(unsafe { (*device_ptr).device_type }, ArrowDeviceType::Cpu as i32);
140 let imported = unsafe {
141 import_point_cloud_device_array(schema_ptr, device_ptr, SpatialMetadata::default())
142 }
143 .unwrap();
144 assert_eq!(imported.field("x").unwrap().as_f32().unwrap(), &[1.0]);
145 }
146}