blob: bb4f4a3ae4e888de36efead4162ef1719d73042a [file] [log] [blame]
Bryan Duxburyc0166282009-02-02 00:48:17 +00001#include <ruby.h>
2#include <stdbool.h>
Bryan Duxbury1e80d442009-02-03 18:16:54 +00003#include <stdint.h>
Bryan Duxburyc0166282009-02-02 00:48:17 +00004#include <constants.h>
5#include <struct.h>
Bryan Duxburyd815c212009-03-19 18:57:43 +00006#include "macros.h"
Bryan Duxburyc0166282009-02-02 00:48:17 +00007
8VALUE rb_thrift_binary_proto_native_qmark(VALUE self) {
9 return Qtrue;
10}
11
12
13
14static int VERSION_1;
15static int VERSION_MASK;
Kevin Clarkead33822009-02-04 22:43:59 +000016static int TYPE_MASK;
Bryan Duxburyc0166282009-02-02 00:48:17 +000017static int BAD_VERSION;
18
19static void write_byte_direct(VALUE trans, int8_t b) {
20 WRITE(trans, (char*)&b, 1);
21}
22
23static void write_i16_direct(VALUE trans, int16_t value) {
24 char data[2];
25
26 data[1] = value;
27 data[0] = (value >> 8);
28
29 WRITE(trans, data, 2);
30}
31
32static void write_i32_direct(VALUE trans, int32_t value) {
33 char data[4];
34
35 data[3] = value;
36 data[2] = (value >> 8);
37 data[1] = (value >> 16);
38 data[0] = (value >> 24);
39
40 WRITE(trans, data, 4);
41}
42
43
44static void write_i64_direct(VALUE trans, int64_t value) {
45 char data[8];
46
47 data[7] = value;
48 data[6] = (value >> 8);
49 data[5] = (value >> 16);
50 data[4] = (value >> 24);
51 data[3] = (value >> 32);
52 data[2] = (value >> 40);
53 data[1] = (value >> 48);
54 data[0] = (value >> 56);
55
56 WRITE(trans, data, 8);
57}
58
59static void write_string_direct(VALUE trans, VALUE str) {
60 write_i32_direct(trans, RSTRING(str)->len);
61 rb_funcall(trans, write_method_id, 1, str);
62}
63
64//--------------------------------
65// interface writing methods
66//--------------------------------
67
68VALUE rb_thrift_binary_proto_write_message_end(VALUE self) {
69 return Qnil;
70}
71
72VALUE rb_thrift_binary_proto_write_struct_begin(VALUE self, VALUE name) {
73 return Qnil;
74}
75
76VALUE rb_thrift_binary_proto_write_struct_end(VALUE self) {
77 return Qnil;
78}
79
80VALUE rb_thrift_binary_proto_write_field_end(VALUE self) {
81 return Qnil;
82}
83
84VALUE rb_thrift_binary_proto_write_map_end(VALUE self) {
85 return Qnil;
86}
87
88VALUE rb_thrift_binary_proto_write_list_end(VALUE self) {
89 return Qnil;
90}
91
92VALUE rb_thrift_binary_proto_write_set_end(VALUE self) {
93 return Qnil;
94}
95
96VALUE rb_thrift_binary_proto_write_message_begin(VALUE self, VALUE name, VALUE type, VALUE seqid) {
97 VALUE trans = GET_TRANSPORT(self);
Kevin Clarkead33822009-02-04 22:43:59 +000098 VALUE strict_write = GET_STRICT_WRITE(self);
99
100 if (strict_write == Qtrue) {
101 write_i32_direct(trans, VERSION_1 | FIX2INT(type));
102 write_string_direct(trans, name);
103 write_i32_direct(trans, FIX2INT(seqid));
104 } else {
105 write_string_direct(trans, name);
106 write_byte_direct(trans, type);
107 write_i32_direct(trans, FIX2INT(seqid));
108 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000109
110 return Qnil;
111}
112
113VALUE rb_thrift_binary_proto_write_field_begin(VALUE self, VALUE name, VALUE type, VALUE id) {
114 VALUE trans = GET_TRANSPORT(self);
115 write_byte_direct(trans, FIX2INT(type));
116 write_i16_direct(trans, FIX2INT(id));
117
118 return Qnil;
119}
120
121VALUE rb_thrift_binary_proto_write_field_stop(VALUE self) {
122 write_byte_direct(GET_TRANSPORT(self), TTYPE_STOP);
123 return Qnil;
124}
125
126VALUE rb_thrift_binary_proto_write_map_begin(VALUE self, VALUE ktype, VALUE vtype, VALUE size) {
127 VALUE trans = GET_TRANSPORT(self);
128 write_byte_direct(trans, FIX2INT(ktype));
129 write_byte_direct(trans, FIX2INT(vtype));
130 write_i32_direct(trans, FIX2INT(size));
131
132 return Qnil;
133}
134
135VALUE rb_thrift_binary_proto_write_list_begin(VALUE self, VALUE etype, VALUE size) {
136 VALUE trans = GET_TRANSPORT(self);
137 write_byte_direct(trans, FIX2INT(etype));
138 write_i32_direct(trans, FIX2INT(size));
139
140 return Qnil;
141}
142
143VALUE rb_thrift_binary_proto_write_set_begin(VALUE self, VALUE etype, VALUE size) {
144 rb_thrift_binary_proto_write_list_begin(self, etype, size);
145 return Qnil;
146}
147
148VALUE rb_thrift_binary_proto_write_bool(VALUE self, VALUE b) {
149 write_byte_direct(GET_TRANSPORT(self), RTEST(b) ? 1 : 0);
150 return Qnil;
151}
152
153VALUE rb_thrift_binary_proto_write_byte(VALUE self, VALUE byte) {
154 CHECK_NIL(byte);
155 write_byte_direct(GET_TRANSPORT(self), NUM2INT(byte));
156 return Qnil;
157}
158
159VALUE rb_thrift_binary_proto_write_i16(VALUE self, VALUE i16) {
160 CHECK_NIL(i16);
161 write_i16_direct(GET_TRANSPORT(self), FIX2INT(i16));
162 return Qnil;
163}
164
165VALUE rb_thrift_binary_proto_write_i32(VALUE self, VALUE i32) {
166 CHECK_NIL(i32);
167 write_i32_direct(GET_TRANSPORT(self), NUM2INT(i32));
168 return Qnil;
169}
170
171VALUE rb_thrift_binary_proto_write_i64(VALUE self, VALUE i64) {
172 CHECK_NIL(i64);
173 write_i64_direct(GET_TRANSPORT(self), NUM2LL(i64));
174 return Qnil;
175}
176
177VALUE rb_thrift_binary_proto_write_double(VALUE self, VALUE dub) {
178 CHECK_NIL(dub);
179 // Unfortunately, bitwise_cast doesn't work in C. Bad C!
180 union {
181 double f;
182 int64_t t;
183 } transfer;
184 transfer.f = RFLOAT(rb_Float(dub))->value;
185 write_i64_direct(GET_TRANSPORT(self), transfer.t);
186
187 return Qnil;
188}
189
190VALUE rb_thrift_binary_proto_write_string(VALUE self, VALUE str) {
191 CHECK_NIL(str);
192 VALUE trans = GET_TRANSPORT(self);
193 // write_i32_direct(trans, RSTRING(str)->len);
194 // rb_funcall(trans, write_method_id, 1, str);
195 write_string_direct(trans, str);
196 return Qnil;
197}
198
199//---------------------------------------
200// interface reading methods
201//---------------------------------------
202
Bryan Duxburyc0166282009-02-02 00:48:17 +0000203VALUE rb_thrift_binary_proto_read_string(VALUE self);
204VALUE rb_thrift_binary_proto_read_byte(VALUE self);
205VALUE rb_thrift_binary_proto_read_i32(VALUE self);
206VALUE rb_thrift_binary_proto_read_i16(VALUE self);
207
208static char read_byte_direct(VALUE self) {
209 return (RSTRING(READ(self, 1))->ptr)[0];
210}
211
212static int16_t read_i16_direct(VALUE self) {
213 VALUE buf = READ(self, 2);
214 return (int16_t)(((uint8_t)(RSTRING(buf)->ptr[1])) | ((uint16_t)((RSTRING(buf)->ptr[0]) << 8)));
215}
216
217static int32_t read_i32_direct(VALUE self) {
218 VALUE buf = READ(self, 4);
219 return ((uint8_t)(RSTRING(buf)->ptr[3])) |
220 (((uint8_t)(RSTRING(buf)->ptr[2])) << 8) |
221 (((uint8_t)(RSTRING(buf)->ptr[1])) << 16) |
222 (((uint8_t)(RSTRING(buf)->ptr[0])) << 24);
223}
224
225static int64_t read_i64_direct(VALUE self) {
226 uint64_t hi = read_i32_direct(self);
227 uint32_t lo = read_i32_direct(self);
228 return (hi << 32) | lo;
229}
230
231static VALUE get_protocol_exception(VALUE code, VALUE message) {
232 VALUE args[2];
233 args[0] = code;
234 args[1] = message;
235 return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
236}
237
238VALUE rb_thrift_binary_proto_read_message_end(VALUE self) {
239 return Qnil;
240}
241
242VALUE rb_thift_binary_proto_read_struct_begin(VALUE self) {
243 return Qnil;
244}
245
246VALUE rb_thift_binary_proto_read_struct_end(VALUE self) {
247 return Qnil;
248}
249
250VALUE rb_thift_binary_proto_read_field_end(VALUE self) {
251 return Qnil;
252}
253
254VALUE rb_thift_binary_proto_read_map_end(VALUE self) {
255 return Qnil;
256}
257
258VALUE rb_thift_binary_proto_read_list_end(VALUE self) {
259 return Qnil;
260}
261
262VALUE rb_thift_binary_proto_read_set_end(VALUE self) {
263 return Qnil;
264}
265
266VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) {
Kevin Clarkead33822009-02-04 22:43:59 +0000267 VALUE strict_read = GET_STRICT_READ(self);
268 VALUE name, seqid;
269 int type;
Bryan Duxburyc0166282009-02-02 00:48:17 +0000270
Kevin Clarkead33822009-02-04 22:43:59 +0000271 int version = read_i32_direct(self);
272
273 if (version < 0) {
274 if ((version & VERSION_MASK) != VERSION_1) {
275 rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier")));
276 }
277 type = version & TYPE_MASK;
278 name = rb_thrift_binary_proto_read_string(self);
279 seqid = rb_thrift_binary_proto_read_i32(self);
280 } else {
281 if (strict_read == Qtrue) {
282 rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("No version identifier, old protocol client?")));
283 }
284 name = READ(self, version);
285 type = rb_thrift_binary_proto_read_byte(self);
286 seqid = rb_thrift_binary_proto_read_i32(self);
287 }
Bryan Duxburyc0166282009-02-02 00:48:17 +0000288
289 return rb_ary_new3(3, name, INT2FIX(type), seqid);
290}
291
292VALUE rb_thrift_binary_proto_read_field_begin(VALUE self) {
293 int type = read_byte_direct(self);
294 if (type == TTYPE_STOP) {
295 return rb_ary_new3(3, Qnil, INT2FIX(type), INT2FIX(0));
296 } else {
297 VALUE id = rb_thrift_binary_proto_read_i16(self);
298 return rb_ary_new3(3, Qnil, INT2FIX(type), id);
299 }
300}
301
302VALUE rb_thrift_binary_proto_read_map_begin(VALUE self) {
303 VALUE ktype = rb_thrift_binary_proto_read_byte(self);
304 VALUE vtype = rb_thrift_binary_proto_read_byte(self);
305 VALUE size = rb_thrift_binary_proto_read_i32(self);
306 return rb_ary_new3(3, ktype, vtype, size);
307}
308
309VALUE rb_thrift_binary_proto_read_list_begin(VALUE self) {
310 VALUE etype = rb_thrift_binary_proto_read_byte(self);
311 VALUE size = rb_thrift_binary_proto_read_i32(self);
312 return rb_ary_new3(2, etype, size);
313}
314
315VALUE rb_thrift_binary_proto_read_set_begin(VALUE self) {
316 return rb_thrift_binary_proto_read_list_begin(self);
317}
318
319VALUE rb_thrift_binary_proto_read_bool(VALUE self) {
320 char byte = read_byte_direct(self);
321 return byte == 1 ? Qtrue : Qfalse;
322}
323
324VALUE rb_thrift_binary_proto_read_byte(VALUE self) {
325 return INT2FIX(read_byte_direct(self));
326}
327
328VALUE rb_thrift_binary_proto_read_i16(VALUE self) {
329 return INT2FIX(read_i16_direct(self));
330}
331
332VALUE rb_thrift_binary_proto_read_i32(VALUE self) {
333 return INT2NUM(read_i32_direct(self));
334}
335
336VALUE rb_thrift_binary_proto_read_i64(VALUE self) {
337 return LL2NUM(read_i64_direct(self));
338}
339
340VALUE rb_thrift_binary_proto_read_double(VALUE self) {
341 union {
342 double f;
343 int64_t t;
344 } transfer;
345 transfer.t = read_i64_direct(self);
346 return rb_float_new(transfer.f);
347}
348
349VALUE rb_thrift_binary_proto_read_string(VALUE self) {
350 int size = read_i32_direct(self);
351 return READ(self, size);
352}
353
354void Init_binary_protocol_accelerated() {
355 VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol"));
356
357 VERSION_1 = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_1")));
358 VERSION_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("VERSION_MASK")));
Kevin Clarkead33822009-02-04 22:43:59 +0000359 TYPE_MASK = rb_num2ll(rb_const_get(thrift_binary_protocol_class, rb_intern("TYPE_MASK")));
Bryan Duxburyc0166282009-02-02 00:48:17 +0000360
361 VALUE bpa_class = rb_define_class_under(thrift_module, "BinaryProtocolAccelerated", thrift_binary_protocol_class);
362
363 rb_define_method(bpa_class, "native?", rb_thrift_binary_proto_native_qmark, 0);
364
365 rb_define_method(bpa_class, "write_message_begin", rb_thrift_binary_proto_write_message_begin, 3);
366 rb_define_method(bpa_class, "write_field_begin", rb_thrift_binary_proto_write_field_begin, 3);
367 rb_define_method(bpa_class, "write_field_stop", rb_thrift_binary_proto_write_field_stop, 0);
368 rb_define_method(bpa_class, "write_map_begin", rb_thrift_binary_proto_write_map_begin, 3);
369 rb_define_method(bpa_class, "write_list_begin", rb_thrift_binary_proto_write_list_begin, 2);
370 rb_define_method(bpa_class, "write_set_begin", rb_thrift_binary_proto_write_set_begin, 2);
371 rb_define_method(bpa_class, "write_byte", rb_thrift_binary_proto_write_byte, 1);
372 rb_define_method(bpa_class, "write_bool", rb_thrift_binary_proto_write_bool, 1);
373 rb_define_method(bpa_class, "write_i16", rb_thrift_binary_proto_write_i16, 1);
374 rb_define_method(bpa_class, "write_i32", rb_thrift_binary_proto_write_i32, 1);
375 rb_define_method(bpa_class, "write_i64", rb_thrift_binary_proto_write_i64, 1);
376 rb_define_method(bpa_class, "write_double", rb_thrift_binary_proto_write_double, 1);
377 rb_define_method(bpa_class, "write_string", rb_thrift_binary_proto_write_string, 1);
378 // unused methods
379 rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0);
380 rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1);
381 rb_define_method(bpa_class, "write_struct_end", rb_thrift_binary_proto_write_struct_end, 0);
382 rb_define_method(bpa_class, "write_field_end", rb_thrift_binary_proto_write_field_end, 0);
383 rb_define_method(bpa_class, "write_map_end", rb_thrift_binary_proto_write_map_end, 0);
384 rb_define_method(bpa_class, "write_list_end", rb_thrift_binary_proto_write_list_end, 0);
385 rb_define_method(bpa_class, "write_set_end", rb_thrift_binary_proto_write_set_end, 0);
386
387
388
389 rb_define_method(bpa_class, "read_message_begin", rb_thrift_binary_proto_read_message_begin, 0);
390 rb_define_method(bpa_class, "read_field_begin", rb_thrift_binary_proto_read_field_begin, 0);
391 rb_define_method(bpa_class, "read_map_begin", rb_thrift_binary_proto_read_map_begin, 0);
392 rb_define_method(bpa_class, "read_list_begin", rb_thrift_binary_proto_read_list_begin, 0);
393 rb_define_method(bpa_class, "read_set_begin", rb_thrift_binary_proto_read_set_begin, 0);
394 rb_define_method(bpa_class, "read_byte", rb_thrift_binary_proto_read_byte, 0);
395 rb_define_method(bpa_class, "read_bool", rb_thrift_binary_proto_read_bool, 0);
396 rb_define_method(bpa_class, "read_i16", rb_thrift_binary_proto_read_i16, 0);
397 rb_define_method(bpa_class, "read_i32", rb_thrift_binary_proto_read_i32, 0);
398 rb_define_method(bpa_class, "read_i64", rb_thrift_binary_proto_read_i64, 0);
399 rb_define_method(bpa_class, "read_double", rb_thrift_binary_proto_read_double, 0);
400 rb_define_method(bpa_class, "read_string", rb_thrift_binary_proto_read_string, 0);
401 // unused methods
402 rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0);
403 rb_define_method(bpa_class, "read_struct_begin", rb_thift_binary_proto_read_struct_begin, 0);
404 rb_define_method(bpa_class, "read_struct_end", rb_thift_binary_proto_read_struct_end, 0);
405 rb_define_method(bpa_class, "read_field_end", rb_thift_binary_proto_read_field_end, 0);
406 rb_define_method(bpa_class, "read_map_end", rb_thift_binary_proto_read_map_end, 0);
407 rb_define_method(bpa_class, "read_list_end", rb_thift_binary_proto_read_list_end, 0);
408 rb_define_method(bpa_class, "read_set_end", rb_thift_binary_proto_read_set_end, 0);
409
410 // set up native method table
411 native_proto_method_table *npmt;
412 npmt = ALLOC(native_proto_method_table);
413
414 npmt->write_field_begin = rb_thrift_binary_proto_write_field_begin;
415 npmt->write_field_stop = rb_thrift_binary_proto_write_field_stop;
416 npmt->write_map_begin = rb_thrift_binary_proto_write_map_begin;
417 npmt->write_list_begin = rb_thrift_binary_proto_write_list_begin;
418 npmt->write_set_begin = rb_thrift_binary_proto_write_set_begin;
419 npmt->write_byte = rb_thrift_binary_proto_write_byte;
420 npmt->write_bool = rb_thrift_binary_proto_write_bool;
421 npmt->write_i16 = rb_thrift_binary_proto_write_i16;
422 npmt->write_i32 = rb_thrift_binary_proto_write_i32;
423 npmt->write_i64 = rb_thrift_binary_proto_write_i64;
424 npmt->write_double = rb_thrift_binary_proto_write_double;
425 npmt->write_string = rb_thrift_binary_proto_write_string;
426 npmt->write_message_end = rb_thrift_binary_proto_write_message_end;
427 npmt->write_struct_begin = rb_thrift_binary_proto_write_struct_begin;
428 npmt->write_struct_end = rb_thrift_binary_proto_write_struct_end;
429 npmt->write_field_end = rb_thrift_binary_proto_write_field_end;
430 npmt->write_map_end = rb_thrift_binary_proto_write_map_end;
431 npmt->write_list_end = rb_thrift_binary_proto_write_list_end;
432 npmt->write_set_end = rb_thrift_binary_proto_write_set_end;
433
434 npmt->read_message_begin = rb_thrift_binary_proto_read_message_begin;
435 npmt->read_field_begin = rb_thrift_binary_proto_read_field_begin;
436 npmt->read_map_begin = rb_thrift_binary_proto_read_map_begin;
437 npmt->read_list_begin = rb_thrift_binary_proto_read_list_begin;
438 npmt->read_set_begin = rb_thrift_binary_proto_read_set_begin;
439 npmt->read_byte = rb_thrift_binary_proto_read_byte;
440 npmt->read_bool = rb_thrift_binary_proto_read_bool;
441 npmt->read_i16 = rb_thrift_binary_proto_read_i16;
442 npmt->read_i32 = rb_thrift_binary_proto_read_i32;
443 npmt->read_i64 = rb_thrift_binary_proto_read_i64;
444 npmt->read_double = rb_thrift_binary_proto_read_double;
445 npmt->read_string = rb_thrift_binary_proto_read_string;
446 npmt->read_message_end = rb_thrift_binary_proto_read_message_end;
447 npmt->read_struct_begin = rb_thift_binary_proto_read_struct_begin;
448 npmt->read_struct_end = rb_thift_binary_proto_read_struct_end;
449 npmt->read_field_end = rb_thift_binary_proto_read_field_end;
450 npmt->read_map_end = rb_thift_binary_proto_read_map_end;
451 npmt->read_list_end = rb_thift_binary_proto_read_list_end;
452 npmt->read_set_end = rb_thift_binary_proto_read_set_end;
453
454 VALUE method_table_object = Data_Wrap_Struct(rb_cObject, 0, free, npmt);
455 rb_const_set(bpa_class, rb_intern("@native_method_table"), method_table_object);
Bryan Duxbury1e80d442009-02-03 18:16:54 +0000456}