15
15
// specific language governing permissions and limitations
16
16
// under the License.
17
17
18
+ #include <stdint.h>
18
19
#define R_NO_REMAP
19
20
#include <R.h>
20
21
#include <Rinternals.h>
@@ -48,6 +49,50 @@ static SEXP input_stream_owning_xptr(void) {
48
49
return input_stream_xptr ;
49
50
}
50
51
52
+ static void finalize_output_stream_xptr (SEXP output_stream_xptr ) {
53
+ struct ArrowIpcOutputStream * output_stream =
54
+ (struct ArrowIpcOutputStream * )R_ExternalPtrAddr (output_stream_xptr );
55
+ if (output_stream != NULL && output_stream -> release != NULL ) {
56
+ output_stream -> release (output_stream );
57
+ }
58
+
59
+ if (output_stream != NULL ) {
60
+ ArrowFree (output_stream );
61
+ }
62
+ }
63
+
64
+ static SEXP output_stream_owning_xptr (void ) {
65
+ struct ArrowIpcOutputStream * output_stream =
66
+ (struct ArrowIpcOutputStream * )ArrowMalloc (sizeof (struct ArrowIpcOutputStream ));
67
+ output_stream -> release = NULL ;
68
+ SEXP output_stream_xptr =
69
+ PROTECT (R_MakeExternalPtr (output_stream , R_NilValue , R_NilValue ));
70
+ R_RegisterCFinalizer (output_stream_xptr , & finalize_output_stream_xptr );
71
+ UNPROTECT (1 );
72
+ return output_stream_xptr ;
73
+ }
74
+
75
+ static void finalize_writer_xptr (SEXP writer_xptr ) {
76
+ struct ArrowIpcWriter * writer = (struct ArrowIpcWriter * )R_ExternalPtrAddr (writer_xptr );
77
+ if (writer != NULL && writer -> private_data != NULL ) {
78
+ ArrowIpcWriterReset (writer );
79
+ }
80
+
81
+ if (writer != NULL ) {
82
+ ArrowFree (writer );
83
+ }
84
+ }
85
+
86
+ static SEXP writer_owning_xptr (void ) {
87
+ struct ArrowIpcWriter * writer =
88
+ (struct ArrowIpcWriter * )ArrowMalloc (sizeof (struct ArrowIpcWriter ));
89
+ writer -> private_data = NULL ;
90
+ SEXP writer_xptr = PROTECT (R_MakeExternalPtr (writer , R_NilValue , R_NilValue ));
91
+ R_RegisterCFinalizer (writer_xptr , & finalize_writer_xptr );
92
+ UNPROTECT (1 );
93
+ return writer_xptr ;
94
+ }
95
+
51
96
SEXP nanoarrow_c_ipc_array_reader_buffer (SEXP buffer_xptr ) {
52
97
struct ArrowBuffer * buffer = buffer_from_xptr (buffer_xptr );
53
98
@@ -82,7 +127,7 @@ struct ConnectionInputStreamHandler {
82
127
int return_code ;
83
128
};
84
129
85
- static SEXP handle_readbin_error (SEXP cond , void * hdata ) {
130
+ static SEXP handle_readbin_writebin_error (SEXP cond , void * hdata ) {
86
131
struct ConnectionInputStreamHandler * data = (struct ConnectionInputStreamHandler * )hdata ;
87
132
88
133
SEXP fun = PROTECT (Rf_install ("conditionMessage" ));
@@ -103,7 +148,7 @@ static SEXP call_readbin(void* hdata) {
103
148
SEXP n = PROTECT (Rf_ScalarReal ((double )data -> buf_size_bytes ));
104
149
SEXP call = PROTECT (Rf_lang4 (nanoarrow_sym_readbin , data -> con , nanoarrow_ptype_raw , n ));
105
150
106
- SEXP result = PROTECT (Rf_eval (call , R_BaseEnv ));
151
+ SEXP result = PROTECT (Rf_eval (call , nanoarrow_ns_pkg ));
107
152
R_xlen_t bytes_read = Rf_xlength (result );
108
153
memcpy (data -> buf , RAW (result ), bytes_read );
109
154
* (data -> size_read_out ) = bytes_read ;
@@ -112,6 +157,36 @@ static SEXP call_readbin(void* hdata) {
112
157
return R_NilValue ;
113
158
}
114
159
160
+ static SEXP call_writebin (void * hdata ) {
161
+ struct ConnectionInputStreamHandler * data = (struct ConnectionInputStreamHandler * )hdata ;
162
+
163
+ // Write 16MB chunks. This a balance between being small enough not to
164
+ // copy too much of the source unnecessarily and big enough to avoid
165
+ // unnecessary R evaluation overhead.
166
+ int64_t chunk_buffer_size = 16777216 ;
167
+ SEXP chunk_buffer = PROTECT (Rf_allocVector (RAWSXP , chunk_buffer_size ));
168
+ SEXP call = PROTECT (Rf_lang3 (nanoarrow_sym_writebin , chunk_buffer , data -> con ));
169
+ while (data -> buf_size_bytes > chunk_buffer_size ) {
170
+ memcpy (RAW (chunk_buffer ), data -> buf , chunk_buffer_size );
171
+ Rf_eval (call , nanoarrow_ns_pkg );
172
+ data -> buf_size_bytes -= chunk_buffer_size ;
173
+ data -> buf += chunk_buffer_size ;
174
+ }
175
+
176
+ UNPROTECT (2 );
177
+
178
+ // Write remaining bytes
179
+ if (data -> buf_size_bytes > 0 ) {
180
+ chunk_buffer = PROTECT (Rf_allocVector (RAWSXP , data -> buf_size_bytes ));
181
+ call = PROTECT (Rf_lang3 (nanoarrow_sym_writebin , chunk_buffer , data -> con ));
182
+ memcpy (RAW (chunk_buffer ), data -> buf , data -> buf_size_bytes );
183
+ Rf_eval (call , nanoarrow_ns_pkg );
184
+ UNPROTECT (2 );
185
+ }
186
+
187
+ return R_NilValue ;
188
+ }
189
+
115
190
static ArrowErrorCode read_con_input_stream (struct ArrowIpcInputStream * stream ,
116
191
uint8_t * buf , int64_t buf_size_bytes ,
117
192
int64_t * size_read_out ,
@@ -129,14 +204,43 @@ static ArrowErrorCode read_con_input_stream(struct ArrowIpcInputStream* stream,
129
204
data .error = error ;
130
205
data .return_code = NANOARROW_OK ;
131
206
132
- R_tryCatchError (& call_readbin , & data , & handle_readbin_error , & data );
207
+ R_tryCatchError (& call_readbin , & data , & handle_readbin_writebin_error , & data );
208
+ return data .return_code ;
209
+ }
210
+
211
+ static ArrowErrorCode write_con_output_stream (struct ArrowIpcOutputStream * stream ,
212
+ const void * buf , int64_t buf_size_bytes ,
213
+ int64_t * size_write_out ,
214
+ struct ArrowError * error ) {
215
+ if (!nanoarrow_is_main_thread ()) {
216
+ ArrowErrorSet (error , "Can't read from R connection on a non-R thread" );
217
+ return EIO ;
218
+ }
219
+
220
+ struct ConnectionInputStreamHandler data ;
221
+ data .con = (SEXP )stream -> private_data ;
222
+ data .buf = (void * )buf ;
223
+ data .buf_size_bytes = buf_size_bytes ;
224
+ data .size_read_out = NULL ;
225
+ data .error = error ;
226
+ data .return_code = NANOARROW_OK ;
227
+
228
+ R_tryCatchError (& call_writebin , & data , & handle_readbin_writebin_error , & data );
229
+
230
+ // This implementation always blocks until all bytes have been written
231
+ * size_write_out = buf_size_bytes ;
232
+
133
233
return data .return_code ;
134
234
}
135
235
136
236
static void release_con_input_stream (struct ArrowIpcInputStream * stream ) {
137
237
nanoarrow_release_sexp ((SEXP )stream -> private_data );
138
238
}
139
239
240
+ static void release_con_output_stream (struct ArrowIpcOutputStream * stream ) {
241
+ nanoarrow_release_sexp ((SEXP )stream -> private_data );
242
+ }
243
+
140
244
SEXP nanoarrow_c_ipc_array_reader_connection (SEXP con ) {
141
245
SEXP array_stream_xptr = PROTECT (nanoarrow_array_stream_owning_xptr ());
142
246
struct ArrowArrayStream * array_stream =
@@ -153,9 +257,46 @@ SEXP nanoarrow_c_ipc_array_reader_connection(SEXP con) {
153
257
154
258
int code = ArrowIpcArrayStreamReaderInit (array_stream , input_stream , NULL );
155
259
if (code != NANOARROW_OK ) {
156
- Rf_error ("ArrowIpcArrayStreamReaderInit() failed" );
260
+ Rf_error ("ArrowIpcArrayStreamReaderInit() failed with errno %d" , code );
157
261
}
158
262
159
263
UNPROTECT (2 );
160
264
return array_stream_xptr ;
161
265
}
266
+
267
+ SEXP nanoarrow_c_ipc_writer_connection (SEXP con ) {
268
+ SEXP output_stream_xptr = PROTECT (output_stream_owning_xptr ());
269
+ struct ArrowIpcOutputStream * output_stream =
270
+ (struct ArrowIpcOutputStream * )R_ExternalPtrAddr (output_stream_xptr );
271
+
272
+ output_stream -> write = & write_con_output_stream ;
273
+ output_stream -> release = & release_con_output_stream ;
274
+ output_stream -> private_data = (SEXP )con ;
275
+ nanoarrow_preserve_sexp (con );
276
+
277
+ SEXP writer_xptr = PROTECT (writer_owning_xptr ());
278
+ struct ArrowIpcWriter * writer = (struct ArrowIpcWriter * )R_ExternalPtrAddr (writer_xptr );
279
+
280
+ int code = ArrowIpcWriterInit (writer , output_stream );
281
+ if (code != NANOARROW_OK ) {
282
+ Rf_error ("ArrowIpcWriterInit() failed with errno %d" , code );
283
+ }
284
+
285
+ UNPROTECT (2 );
286
+ return writer_xptr ;
287
+ }
288
+
289
+ SEXP nanoarrow_c_ipc_writer_write_stream (SEXP writer_xptr , SEXP array_stream_xptr ) {
290
+ struct ArrowIpcWriter * writer = (struct ArrowIpcWriter * )R_ExternalPtrAddr (writer_xptr );
291
+ struct ArrowArrayStream * array_stream =
292
+ nanoarrow_array_stream_from_xptr (array_stream_xptr );
293
+
294
+ struct ArrowError error ;
295
+ ArrowErrorInit (& error );
296
+ int code = ArrowIpcWriterWriteArrayStream (writer , array_stream , & error );
297
+ if (code != NANOARROW_OK ) {
298
+ Rf_error ("ArrowIpcWriterWriteArrayStream() failed: %s" , error .message );
299
+ }
300
+
301
+ return R_NilValue ;
302
+ }
0 commit comments