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