thrift 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/InstalledFiles +1 -0
  2. data/Makefile +512 -0
  3. data/Makefile.am +3 -1
  4. data/Makefile.in +117 -45
  5. data/Manifest +17 -0
  6. data/Rakefile +6 -8
  7. data/benchmark/gen-rb/benchmark_constants.rb +10 -0
  8. data/benchmark/gen-rb/benchmark_service.rb +80 -0
  9. data/benchmark/gen-rb/benchmark_types.rb +9 -0
  10. data/debug_proto_test/gen-rb/debug_proto_test_constants.rb +273 -0
  11. data/debug_proto_test/gen-rb/debug_proto_test_types.rb +705 -0
  12. data/debug_proto_test/gen-rb/empty_service.rb +24 -0
  13. data/debug_proto_test/gen-rb/inherited.rb +79 -0
  14. data/debug_proto_test/gen-rb/reverse_order_service.rb +82 -0
  15. data/debug_proto_test/gen-rb/service_for_exception_with_a_map.rb +81 -0
  16. data/debug_proto_test/gen-rb/srv.rb +330 -0
  17. data/ext/binary_protocol_accelerated.c +24 -11
  18. data/ext/compact_protocol.c +14 -11
  19. data/ext/constants.h +1 -0
  20. data/ext/memory_buffer.c +56 -1
  21. data/ext/struct.c +76 -19
  22. data/ext/thrift_native.c +2 -0
  23. data/lib/thrift/exceptions.rb +3 -1
  24. data/lib/thrift/protocol/binary_protocol.rb +14 -10
  25. data/lib/thrift/protocol/compact_protocol.rb +7 -4
  26. data/lib/thrift/server/nonblocking_server.rb +15 -5
  27. data/lib/thrift/struct.rb +9 -6
  28. data/lib/thrift/struct_union.rb +47 -14
  29. data/lib/thrift/transport/base_transport.rb +39 -2
  30. data/lib/thrift/transport/buffered_transport.rb +31 -0
  31. data/lib/thrift/transport/framed_transport.rb +26 -0
  32. data/lib/thrift/transport/memory_buffer_transport.rb +29 -0
  33. data/spec/binary_protocol_spec.rb +2 -4
  34. data/spec/gen-rb/nonblocking_service.rb +272 -0
  35. data/spec/gen-rb/thrift_spec_constants.rb +10 -0
  36. data/spec/gen-rb/thrift_spec_types.rb +345 -0
  37. data/spec/spec_helper.rb +1 -3
  38. data/thrift.gemspec +10 -11
  39. data/tmp/thrift-0.7.0.gem +0 -0
  40. metadata +22 -8
data/ext/constants.h CHANGED
@@ -74,6 +74,7 @@ extern ID write_field_stop_method_id;
74
74
  extern ID skip_method_id;
75
75
  extern ID write_method_id;
76
76
  extern ID read_all_method_id;
77
+ extern ID read_into_buffer_method_id;
77
78
  extern ID native_qmark_method_id;
78
79
 
79
80
  extern ID fields_const_id;
data/ext/memory_buffer.c CHANGED
@@ -30,6 +30,11 @@ int GARBAGE_BUFFER_SIZE;
30
30
 
31
31
  #define GET_BUF(self) rb_ivar_get(self, buf_ivar_id)
32
32
 
33
+ VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str);
34
+ VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value);
35
+ VALUE rb_thrift_memory_buffer_read_byte(VALUE self);
36
+ VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value);
37
+
33
38
  VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) {
34
39
  VALUE buf = GET_BUF(self);
35
40
  rb_str_buf_cat(buf, RSTRING_PTR(str), RSTRING_LEN(str));
@@ -53,19 +58,69 @@ VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) {
53
58
  rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
54
59
  index = 0;
55
60
  }
61
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
56
62
 
57
63
  if (RSTRING_LEN(data) < length) {
58
64
  rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
59
65
  }
60
66
 
61
- rb_ivar_set(self, index_ivar_id, INT2FIX(index));
62
67
  return data;
63
68
  }
64
69
 
70
+ VALUE rb_thrift_memory_buffer_read_byte(VALUE self) {
71
+ VALUE index_value = rb_ivar_get(self, index_ivar_id);
72
+ int index = FIX2INT(index_value);
73
+
74
+ VALUE buf = GET_BUF(self);
75
+ if (index >= RSTRING_LEN(buf)) {
76
+ rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
77
+ }
78
+ char byte = RSTRING_PTR(buf)[index++];
79
+
80
+ if (index >= GARBAGE_BUFFER_SIZE) {
81
+ rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
82
+ index = 0;
83
+ }
84
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
85
+
86
+ int result = (int) byte;
87
+ return INT2FIX(result);
88
+ }
89
+
90
+ VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value) {
91
+ int i = 0;
92
+ int size = FIX2INT(size_value);
93
+ int index;
94
+ VALUE buf = GET_BUF(self);
95
+
96
+ while (i < size) {
97
+ index = FIX2INT(rb_ivar_get(self, index_ivar_id));
98
+ if (index >= RSTRING_LEN(buf)) {
99
+ rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
100
+ }
101
+ char byte = RSTRING_PTR(buf)[index++];
102
+
103
+ if (index >= GARBAGE_BUFFER_SIZE) {
104
+ rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
105
+ index = 0;
106
+ }
107
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
108
+
109
+ if (i >= RSTRING_LEN(buffer_value)) {
110
+ rb_raise(rb_eIndexError, "index %d out of string", i);
111
+ }
112
+ ((char*)RSTRING_PTR(buffer_value))[i] = byte;
113
+ i++;
114
+ }
115
+ return INT2FIX(i);
116
+ }
117
+
65
118
  void Init_memory_buffer() {
66
119
  VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBufferTransport"));
67
120
  rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1);
68
121
  rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1);
122
+ rb_define_method(thrift_memory_buffer_class, "read_byte", rb_thrift_memory_buffer_read_byte, 0);
123
+ rb_define_method(thrift_memory_buffer_class, "read_into_buffer", rb_thrift_memory_buffer_read_into_buffer, 2);
69
124
 
70
125
  buf_ivar_id = rb_intern("@buf");
71
126
  index_ivar_id = rb_intern("@index");
data/ext/struct.c CHANGED
@@ -55,6 +55,7 @@ ID setvalue_id;
55
55
 
56
56
  ID to_s_method_id;
57
57
  ID name_to_id_method_id;
58
+ static ID sorted_field_ids_method_id;
58
59
 
59
60
  #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
60
61
  #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
@@ -375,13 +376,11 @@ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
375
376
 
376
377
  // iterate through all the fields here
377
378
  VALUE struct_fields = STRUCT_FIELDS(self);
378
-
379
- VALUE struct_field_ids_unordered = rb_funcall(struct_fields, keys_method_id, 0);
380
- VALUE struct_field_ids_ordered = rb_funcall(struct_field_ids_unordered, sort_method_id, 0);
379
+ VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
381
380
 
382
381
  int i = 0;
383
- for (i=0; i < RARRAY_LEN(struct_field_ids_ordered); i++) {
384
- VALUE field_id = rb_ary_entry(struct_field_ids_ordered, i);
382
+ for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
383
+ VALUE field_id = rb_ary_entry(sorted_field_ids, i);
385
384
 
386
385
  VALUE field_info = rb_hash_aref(struct_fields, field_id);
387
386
 
@@ -414,6 +413,8 @@ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
414
413
 
415
414
  static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
416
415
  static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
416
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
417
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
417
418
 
418
419
  static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
419
420
  char name_buf[RSTRING_LEN(field_name) + 1];
@@ -424,6 +425,23 @@ static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
424
425
  rb_ivar_set(obj, rb_intern(name_buf), value);
425
426
  }
426
427
 
428
+ // Helper method to skip the contents of a map (assumes the map header has been read).
429
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
430
+ int i;
431
+ for (i = 0; i < size; i++) {
432
+ rb_funcall(protocol, skip_method_id, 1, key_type_value);
433
+ rb_funcall(protocol, skip_method_id, 1, value_type_value);
434
+ }
435
+ }
436
+
437
+ // Helper method to skip the contents of a list or set (assumes the list/set header has been read).
438
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
439
+ int i;
440
+ for (i = 0; i < size; i++) {
441
+ rb_funcall(protocol, skip_method_id, 1, element_type_value);
442
+ }
443
+ }
444
+
427
445
  static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
428
446
  VALUE result = Qnil;
429
447
 
@@ -458,18 +476,30 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
458
476
  int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
459
477
  int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
460
478
 
479
+ // Check the declared key and value types against the expected ones and skip the map contents
480
+ // if the types don't match.
461
481
  VALUE key_info = rb_hash_aref(field_info, key_sym);
462
482
  VALUE value_info = rb_hash_aref(field_info, value_sym);
463
483
 
464
- result = rb_hash_new();
484
+ if (!NIL_P(key_info) && !NIL_P(value_info)) {
485
+ int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
486
+ int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
487
+ if (specified_key_type == key_ttype && specified_value_type == value_ttype) {
488
+ result = rb_hash_new();
465
489
 
466
- for (i = 0; i < num_entries; ++i) {
467
- VALUE key, val;
490
+ for (i = 0; i < num_entries; ++i) {
491
+ VALUE key, val;
468
492
 
469
- key = read_anything(protocol, key_ttype, key_info);
470
- val = read_anything(protocol, value_ttype, value_info);
493
+ key = read_anything(protocol, key_ttype, key_info);
494
+ val = read_anything(protocol, value_ttype, value_info);
471
495
 
472
- rb_hash_aset(result, key, val);
496
+ rb_hash_aset(result, key, val);
497
+ }
498
+ } else {
499
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
500
+ }
501
+ } else {
502
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
473
503
  }
474
504
 
475
505
  default_read_map_end(protocol);
@@ -479,10 +509,23 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
479
509
  VALUE list_header = default_read_list_begin(protocol);
480
510
  int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
481
511
  int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
482
- result = rb_ary_new2(num_elements);
483
512
 
484
- for (i = 0; i < num_elements; ++i) {
485
- rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
513
+ // Check the declared element type against the expected one and skip the list contents
514
+ // if the types don't match.
515
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
516
+ if (!NIL_P(element_info)) {
517
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
518
+ if (specified_element_type == element_ttype) {
519
+ result = rb_ary_new2(num_elements);
520
+
521
+ for (i = 0; i < num_elements; ++i) {
522
+ rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
523
+ }
524
+ } else {
525
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
526
+ }
527
+ } else {
528
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
486
529
  }
487
530
 
488
531
  default_read_list_end(protocol);
@@ -493,15 +536,28 @@ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
493
536
  VALUE set_header = default_read_set_begin(protocol);
494
537
  int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
495
538
  int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
496
- items = rb_ary_new2(num_elements);
497
539
 
498
- for (i = 0; i < num_elements; ++i) {
499
- rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
540
+ // Check the declared element type against the expected one and skip the set contents
541
+ // if the types don't match.
542
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
543
+ if (!NIL_P(element_info)) {
544
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
545
+ if (specified_element_type == element_ttype) {
546
+ items = rb_ary_new2(num_elements);
547
+
548
+ for (i = 0; i < num_elements; ++i) {
549
+ rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
550
+ }
551
+
552
+ result = rb_class_new_instance(1, &items, rb_cSet);
553
+ } else {
554
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
555
+ }
556
+ } else {
557
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
500
558
  }
501
559
 
502
560
  default_read_set_end(protocol);
503
-
504
- result = rb_class_new_instance(1, &items, rb_cSet);
505
561
  } else {
506
562
  rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
507
563
  }
@@ -657,4 +713,5 @@ void Init_struct() {
657
713
 
658
714
  to_s_method_id = rb_intern("to_s");
659
715
  name_to_id_method_id = rb_intern("name_to_id");
716
+ sorted_field_ids_method_id = rb_intern("sorted_field_ids");
660
717
  }
data/ext/thrift_native.c CHANGED
@@ -88,6 +88,7 @@ ID write_field_stop_method_id;
88
88
  ID skip_method_id;
89
89
  ID write_method_id;
90
90
  ID read_all_method_id;
91
+ ID read_into_buffer_method_id;
91
92
  ID native_qmark_method_id;
92
93
 
93
94
  // constant ids
@@ -170,6 +171,7 @@ void Init_thrift_native() {
170
171
  skip_method_id = rb_intern("skip");
171
172
  write_method_id = rb_intern("write");
172
173
  read_all_method_id = rb_intern("read_all");
174
+ read_into_buffer_method_id = rb_intern("read_into_buffer");
173
175
  native_qmark_method_id = rb_intern("native?");
174
176
 
175
177
  // constant ids
@@ -35,6 +35,8 @@ module Thrift
35
35
  WRONG_METHOD_NAME = 3
36
36
  BAD_SEQUENCE_ID = 4
37
37
  MISSING_RESULT = 5
38
+ INTERNAL_ERROR = 6
39
+ PROTOCOL_ERROR = 7
38
40
 
39
41
  attr_reader :type
40
42
 
@@ -79,4 +81,4 @@ module Thrift
79
81
  end
80
82
 
81
83
  end
82
- end
84
+ end
@@ -29,6 +29,11 @@ module Thrift
29
29
  super(trans)
30
30
  @strict_read = strict_read
31
31
  @strict_write = strict_write
32
+
33
+ # Pre-allocated read buffer for fixed-size read methods. Needs to be at least 8 bytes long for
34
+ # read_i64() and read_double().
35
+ @rbuf = "\0" * 8
36
+ @rbuf.force_encoding("BINARY") if @rbuf.respond_to?(:force_encoding)
32
37
  end
33
38
 
34
39
  def write_message_begin(name, type, seqid)
@@ -165,8 +170,7 @@ module Thrift
165
170
  end
166
171
 
167
172
  def read_byte
168
- dat = trans.read_all(1)
169
- val = dat[0].ord
173
+ val = trans.read_byte
170
174
  if (val > 0x7f)
171
175
  val = 0 - ((val - 1) ^ 0xff)
172
176
  end
@@ -174,8 +178,8 @@ module Thrift
174
178
  end
175
179
 
176
180
  def read_i16
177
- dat = trans.read_all(2)
178
- val, = dat.unpack('n')
181
+ trans.read_into_buffer(@rbuf, 2)
182
+ val, = @rbuf.unpack('n')
179
183
  if (val > 0x7fff)
180
184
  val = 0 - ((val - 1) ^ 0xffff)
181
185
  end
@@ -183,8 +187,8 @@ module Thrift
183
187
  end
184
188
 
185
189
  def read_i32
186
- dat = trans.read_all(4)
187
- val, = dat.unpack('N')
190
+ trans.read_into_buffer(@rbuf, 4)
191
+ val, = @rbuf.unpack('N')
188
192
  if (val > 0x7fffffff)
189
193
  val = 0 - ((val - 1) ^ 0xffffffff)
190
194
  end
@@ -192,8 +196,8 @@ module Thrift
192
196
  end
193
197
 
194
198
  def read_i64
195
- dat = trans.read_all(8)
196
- hi, lo = dat.unpack('N2')
199
+ trans.read_into_buffer(@rbuf, 8)
200
+ hi, lo = @rbuf.unpack('N2')
197
201
  if (hi > 0x7fffffff)
198
202
  hi ^= 0xffffffff
199
203
  lo ^= 0xffffffff
@@ -204,8 +208,8 @@ module Thrift
204
208
  end
205
209
 
206
210
  def read_double
207
- dat = trans.read_all(8)
208
- val = dat.unpack('G').first
211
+ trans.read_into_buffer(@rbuf, 8)
212
+ val = @rbuf.unpack('G').first
209
213
  val
210
214
  end
211
215
 
@@ -98,6 +98,10 @@ module Thrift
98
98
 
99
99
  @last_field = [0]
100
100
  @boolean_value = nil
101
+
102
+ # Pre-allocated read buffer for read_double().
103
+ @rbuf = "\0" * 8
104
+ @rbuf.force_encoding("BINARY") if @rbuf.respond_to?(:force_encoding)
101
105
  end
102
106
 
103
107
  def write_message_begin(name, type, seqid)
@@ -302,8 +306,7 @@ module Thrift
302
306
  end
303
307
 
304
308
  def read_byte
305
- dat = trans.read_all(1)
306
- val = dat[0]
309
+ val = trans.read_byte
307
310
  if (val > 0x7f)
308
311
  val = 0 - ((val - 1) ^ 0xff)
309
312
  end
@@ -323,8 +326,8 @@ module Thrift
323
326
  end
324
327
 
325
328
  def read_double
326
- dat = trans.read_all(8)
327
- val = dat.reverse.unpack('G').first
329
+ trans.read_into_buffer(@rbuf, 8)
330
+ val = @rbuf.reverse.unpack('G').first
328
331
  val
329
332
  end
330
333
 
@@ -44,7 +44,13 @@ module Thrift
44
44
  begin
45
45
  loop do
46
46
  break if @server_transport.closed?
47
- rd, = select([@server_transport], nil, nil, 0.1)
47
+ begin
48
+ rd, = select([@server_transport], nil, nil, 0.1)
49
+ rescue Errno::EBADF => e
50
+ # In Ruby 1.9, calling @server_transport.close in shutdown paths causes the select() to raise an
51
+ # Errno::EBADF. If this happens, ignore it and retry the loop.
52
+ break
53
+ end
48
54
  next if rd.nil?
49
55
  socket = @server_transport.accept
50
56
  @logger.debug "Accepted socket: #{socket.inspect}"
@@ -146,10 +152,14 @@ module Thrift
146
152
  break if read_signals == :shutdown
147
153
  end
148
154
  rd.each do |fd|
149
- if fd.handle.eof?
155
+ begin
156
+ if fd.handle.eof?
157
+ remove_connection fd
158
+ else
159
+ read_connection fd
160
+ end
161
+ rescue Errno::ECONNRESET
150
162
  remove_connection fd
151
- else
152
- read_connection fd
153
163
  end
154
164
  end
155
165
  end
@@ -292,4 +302,4 @@ module Thrift
292
302
  end
293
303
  end
294
304
  end
295
- end
305
+ end
data/lib/thrift/struct.rb CHANGED
@@ -55,7 +55,7 @@ module Thrift
55
55
  end
56
56
 
57
57
  def fields_with_default_values
58
- fields_with_default_values = self.class.instance_variable_get("@fields_with_default_values")
58
+ fields_with_default_values = self.class.instance_variable_get(:@fields_with_default_values)
59
59
  unless fields_with_default_values
60
60
  fields_with_default_values = {}
61
61
  struct_fields.each do |fid, field_def|
@@ -63,7 +63,7 @@ module Thrift
63
63
  fields_with_default_values[field_def[:name]] = field_def[:default]
64
64
  end
65
65
  end
66
- self.class.instance_variable_set("@fields_with_default_values", fields_with_default_values)
66
+ self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values)
67
67
  end
68
68
  fields_with_default_values
69
69
  end
@@ -114,9 +114,10 @@ module Thrift
114
114
  end
115
115
 
116
116
  def ==(other)
117
+ return false if other.nil?
117
118
  each_field do |fid, field_info|
118
119
  name = field_info[:name]
119
- return false unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
120
+ return false unless other.respond_to?(name) && self.send(name) == other.send(name)
120
121
  end
121
122
  true
122
123
  end
@@ -125,13 +126,15 @@ module Thrift
125
126
  self.class == other.class && self == other
126
127
  end
127
128
 
129
+ # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class.
128
130
  def hash
129
- field_values = []
131
+ total = 17
130
132
  each_field do |fid, field_info|
131
133
  name = field_info[:name]
132
- field_values << self.instance_variable_get("@#{name}")
134
+ value = self.send(name)
135
+ total = (total * 37 + value.hash) & 0xffffffff
133
136
  end
134
- field_values.hash
137
+ total
135
138
  end
136
139
 
137
140
  def differences(other)
@@ -21,19 +21,28 @@ require 'set'
21
21
  module Thrift
22
22
  module Struct_Union
23
23
  def name_to_id(name)
24
- names_to_ids = self.class.instance_variable_get("@names_to_ids")
24
+ names_to_ids = self.class.instance_variable_get(:@names_to_ids)
25
25
  unless names_to_ids
26
26
  names_to_ids = {}
27
27
  struct_fields.each do |fid, field_def|
28
28
  names_to_ids[field_def[:name]] = fid
29
29
  end
30
- self.class.instance_variable_set("@names_to_ids", names_to_ids)
30
+ self.class.instance_variable_set(:@names_to_ids, names_to_ids)
31
31
  end
32
32
  names_to_ids[name]
33
33
  end
34
34
 
35
+ def sorted_field_ids
36
+ sorted_field_ids = self.class.instance_variable_get(:@sorted_field_ids)
37
+ unless sorted_field_ids
38
+ sorted_field_ids = struct_fields.keys.sort
39
+ self.class.instance_variable_set(:@sorted_field_ids, sorted_field_ids)
40
+ end
41
+ sorted_field_ids
42
+ end
43
+
35
44
  def each_field
36
- struct_fields.keys.sort.each do |fid|
45
+ sorted_field_ids.each do |fid|
37
46
  data = struct_fields[fid]
38
47
  yield fid, data
39
48
  end
@@ -46,25 +55,49 @@ module Thrift
46
55
  value.read(iprot)
47
56
  when Types::MAP
48
57
  key_type, val_type, size = iprot.read_map_begin
49
- value = {}
50
- size.times do
51
- k = read_field(iprot, field_info(field[:key]))
52
- v = read_field(iprot, field_info(field[:value]))
53
- value[k] = v
58
+ # Skip the map contents if the declared key or value types don't match the expected ones.
59
+ if (key_type != field[:key][:type] || val_type != field[:value][:type])
60
+ size.times do
61
+ iprot.skip(key_type)
62
+ iprot.skip(val_type)
63
+ end
64
+ value = nil
65
+ else
66
+ value = {}
67
+ size.times do
68
+ k = read_field(iprot, field_info(field[:key]))
69
+ v = read_field(iprot, field_info(field[:value]))
70
+ value[k] = v
71
+ end
54
72
  end
55
73
  iprot.read_map_end
56
74
  when Types::LIST
57
75
  e_type, size = iprot.read_list_begin
58
- value = Array.new(size) do |n|
59
- read_field(iprot, field_info(field[:element]))
76
+ # Skip the list contents if the declared element type doesn't match the expected one.
77
+ if (e_type != field[:element][:type])
78
+ size.times do
79
+ iprot.skip(e_type)
80
+ end
81
+ value = nil
82
+ else
83
+ value = Array.new(size) do |n|
84
+ read_field(iprot, field_info(field[:element]))
85
+ end
60
86
  end
61
87
  iprot.read_list_end
62
88
  when Types::SET
63
89
  e_type, size = iprot.read_set_begin
64
- value = Set.new
65
- size.times do
66
- element = read_field(iprot, field_info(field[:element]))
67
- value << element
90
+ # Skip the set contents if the declared element type doesn't match the expected one.
91
+ if (e_type != field[:element][:type])
92
+ size.times do
93
+ iprot.skip(e_type)
94
+ end
95
+ else
96
+ value = Set.new
97
+ size.times do
98
+ element = read_field(iprot, field_info(field[:element]))
99
+ value << element
100
+ end
68
101
  end
69
102
  iprot.read_set_end
70
103
  else
@@ -34,6 +34,26 @@ module Thrift
34
34
  end
35
35
  end
36
36
 
37
+ module TransportUtils
38
+ if RUBY_VERSION >= '1.9'
39
+ def self.get_string_byte(string, index)
40
+ string.getbyte(index)
41
+ end
42
+
43
+ def self.set_string_byte(string, index, byte)
44
+ string.setbyte(index, byte)
45
+ end
46
+ else
47
+ def self.get_string_byte(string, index)
48
+ string[index]
49
+ end
50
+
51
+ def self.set_string_byte(string, index, byte)
52
+ string[index] = byte
53
+ end
54
+ end
55
+ end
56
+
37
57
  class BaseTransport
38
58
  def open?; end
39
59
 
@@ -45,9 +65,26 @@ module Thrift
45
65
  raise NotImplementedError
46
66
  end
47
67
 
68
+ # Returns an unsigned byte as a Fixnum in the range (0..255).
69
+ def read_byte
70
+ buf = read_all(1)
71
+ return ::Thrift::TransportUtils.get_string_byte(buf, 0)
72
+ end
73
+
74
+ # Reads size bytes and copies them into buffer[0..size].
75
+ def read_into_buffer(buffer, size)
76
+ tmp = read_all(size)
77
+ i = 0
78
+ tmp.each_byte do |byte|
79
+ ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
80
+ i += 1
81
+ end
82
+ i
83
+ end
84
+
48
85
  def read_all(size)
49
- buf = ''
50
-
86
+ return '' if size <= 0
87
+ buf = read(size)
51
88
  while (buf.length < size)
52
89
  chunk = read(size - buf.length)
53
90
  buf << chunk
@@ -55,6 +55,37 @@ module Thrift
55
55
  ret
56
56
  end
57
57
 
58
+ def read_byte
59
+ # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it.
60
+ if @index >= @rbuf.size
61
+ @rbuf = @transport.read(DEFAULT_BUFFER)
62
+ @index = 0
63
+ end
64
+
65
+ # The read buffer has some data now, read a single byte. Using get_string_byte() avoids
66
+ # allocating a temp string of size 1 unnecessarily.
67
+ @index += 1
68
+ return ::Thrift::TransportUtils.get_string_byte(@rbuf, @index - 1)
69
+ end
70
+
71
+ def read_into_buffer(buffer, size)
72
+ i = 0
73
+ while i < size
74
+ # If the read buffer is exhausted, try to read up to DEFAULT_BUFFER more bytes into it.
75
+ if @index >= @rbuf.size
76
+ @rbuf = @transport.read(DEFAULT_BUFFER)
77
+ @index = 0
78
+ end
79
+
80
+ # The read buffer has some data now, so copy bytes over to the output buffer.
81
+ byte = ::Thrift::TransportUtils.get_string_byte(@rbuf, @index)
82
+ ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
83
+ @index += 1
84
+ i += 1
85
+ end
86
+ i
87
+ end
88
+
58
89
  def write(buf)
59
90
  @wbuf << buf
60
91
  end