@@ -17,18 +17,27 @@ use vortex::error::vortex_ensure;
1717use vortex:: session:: VortexSession ;
1818use vortex_cuda:: CudaSession ;
1919use vortex_cuda:: arrow:: ArrowDeviceArray ;
20+ use vortex_cuda:: arrow:: ArrowDeviceArrayStream ;
2021use vortex_cuda:: arrow:: DeviceArrayExt ;
22+ use vortex_cuda:: arrow:: DeviceArrayStreamExt ;
23+ use vortex_ffi:: ffi_runtime;
2124use vortex_ffi:: try_or;
2225use vortex_ffi:: vx_array;
2326use vortex_ffi:: vx_array_ref;
2427use vortex_ffi:: vx_error;
28+ use vortex_ffi:: vx_partition;
29+ use vortex_ffi:: vx_partition_into_array_stream;
2530use vortex_ffi:: vx_session;
2631use vortex_ffi:: vx_session_new_with;
2732use vortex_ffi:: vx_session_ref;
2833
2934const VX_CUDA_OK : c_int = 0 ;
3035const VX_CUDA_ERR : c_int = 1 ;
3136
37+ /// Return a Vortex session with a [`CudaSession`] session variable.
38+ ///
39+ /// If `session` already has CUDA support, this returns a clone of it. Otherwise it
40+ /// returns a new session cloned from `session` with a default [`CudaSession`] attached.
3241fn session_with_cuda ( session : & VortexSession ) -> VortexResult < VortexSession > {
3342 if session. get_opt :: < CudaSession > ( ) . is_some ( ) {
3443 return Ok ( session. clone ( ) ) ;
@@ -100,6 +109,46 @@ pub unsafe extern "C-unwind" fn vx_cuda_array_export_arrow_device(
100109 } )
101110}
102111
112+ /// Consume a Vortex partition and scan it as an Arrow C Device stream.
113+ ///
114+ /// This function takes ownership of `partition`. Callers must not free or reuse it after calling
115+ /// this function, regardless of success or failure.
116+ ///
117+ /// On success returns `0` and writes an owned `ArrowDeviceArrayStream` to `out_stream`. The stream
118+ /// owns the resulting scan iterator. The caller must release the stream through its embedded Arrow
119+ /// `release` callback, and must release each produced `ArrowDeviceArray` through its embedded
120+ /// `ArrowArray.release` callback.
121+ ///
122+ /// On error returns `1` and, when `error_out` is non-null, writes a `vx_error` (free with
123+ /// `vx_error_free`).
124+ ///
125+ /// # Safety
126+ ///
127+ /// `session` must be a valid borrowed handle created by `vortex-ffi`. `partition` must be an owned
128+ /// partition handle created by `vortex-ffi`. `out_stream` must be a valid writable pointer. If
129+ /// `error_out` is non-null, it must be valid for writing one error pointer.
130+ #[ unsafe( no_mangle) ]
131+ pub unsafe extern "C-unwind" fn vx_cuda_partition_scan_arrow_device_stream (
132+ session : * const vx_session ,
133+ partition : * mut vx_partition ,
134+ out_stream : * mut ArrowDeviceArrayStream ,
135+ error_out : * mut * mut vx_error ,
136+ ) -> c_int {
137+ try_or ( error_out, VX_CUDA_ERR , || {
138+ vortex_ensure ! ( !partition. is_null( ) , "null vx_partition" ) ;
139+
140+ let array_stream = unsafe { vx_partition_into_array_stream ( partition) } ?;
141+ vortex_ensure ! ( !out_stream. is_null( ) , "null ArrowDeviceArrayStream output" ) ;
142+
143+ let session = session_with_cuda ( unsafe { vx_session_ref ( session) } ?) ?;
144+ // Drive the stream on the same runtime the partition's scan spawned its work onto.
145+ let device_stream = array_stream. export_device_array_stream ( & session, ffi_runtime ( ) ) ?;
146+
147+ unsafe { ptr:: write ( out_stream, device_stream) } ;
148+ Ok ( VX_CUDA_OK )
149+ } )
150+ }
151+
103152#[ cfg( test) ]
104153mod tests {
105154 use std:: ptr;
0 commit comments