google-protobuf 3.7.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

@@ -3,11 +3,9 @@
3
3
  require 'mkmf'
4
4
 
5
5
  if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
6
- # XOPEN_SOURCE needed for strptime:
7
- # https://stackoverflow.com/questions/35234152/strptime-giving-implicit-declaration-and-undefined-reference
8
- $CFLAGS += " -std=c99 -O3 -DNDEBUG -D_XOPEN_SOURCE=700"
6
+ $CFLAGS += " -std=gnu90 -O3 -DNDEBUG -Wall -Wdeclaration-after-statement -Wsign-compare"
9
7
  else
10
- $CFLAGS += " -std=c99 -O3 -DNDEBUG"
8
+ $CFLAGS += " -std=gnu90 -O3 -DNDEBUG"
11
9
  end
12
10
 
13
11
 
@@ -71,6 +71,9 @@ static VALUE table_key(Map* self, VALUE key,
71
71
  case UPB_TYPE_BYTES:
72
72
  case UPB_TYPE_STRING:
73
73
  // Strings: use string content directly.
74
+ if (TYPE(key) == T_SYMBOL) {
75
+ key = rb_id2str(SYM2ID(key));
76
+ }
74
77
  Check_Type(key, T_STRING);
75
78
  key = native_slot_encode_and_freeze_string(self->key_type, key);
76
79
  *out_key = RSTRING_PTR(key);
@@ -82,7 +85,7 @@ static VALUE table_key(Map* self, VALUE key,
82
85
  case UPB_TYPE_INT64:
83
86
  case UPB_TYPE_UINT32:
84
87
  case UPB_TYPE_UINT64:
85
- native_slot_set(self->key_type, Qnil, buf, key);
88
+ native_slot_set("", self->key_type, Qnil, buf, key);
86
89
  *out_key = buf;
87
90
  *out_length = native_slot_size(self->key_type);
88
91
  break;
@@ -387,7 +390,6 @@ VALUE Map_index(VALUE _self, VALUE key) {
387
390
  */
388
391
  VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
389
392
  Map* self = ruby_to_Map(_self);
390
-
391
393
  char keybuf[TABLE_KEY_BUF_LENGTH];
392
394
  const char* keyval = NULL;
393
395
  size_t length = 0;
@@ -395,8 +397,15 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
395
397
  void* mem;
396
398
  key = table_key(self, key, keybuf, &keyval, &length);
397
399
 
400
+ rb_check_frozen(_self);
401
+
402
+ if (TYPE(value) == T_HASH) {
403
+ VALUE args[1] = { value };
404
+ value = rb_class_new_instance(1, args, self->value_type_class);
405
+ }
406
+
398
407
  mem = value_memory(&v);
399
- native_slot_set(self->value_type, self->value_type_class, mem, value);
408
+ native_slot_set("", self->value_type, self->value_type_class, mem, value);
400
409
 
401
410
  // Replace any existing value by issuing a 'remove' operation first.
402
411
  upb_strtable_remove2(&self->table, keyval, length, NULL);
@@ -439,13 +448,14 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
439
448
  */
440
449
  VALUE Map_delete(VALUE _self, VALUE key) {
441
450
  Map* self = ruby_to_Map(_self);
442
-
443
451
  char keybuf[TABLE_KEY_BUF_LENGTH];
444
452
  const char* keyval = NULL;
445
453
  size_t length = 0;
446
454
  upb_value v;
447
455
  key = table_key(self, key, keybuf, &keyval, &length);
448
456
 
457
+ rb_check_frozen(_self);
458
+
449
459
  if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
450
460
  void* mem = value_memory(&v);
451
461
  return native_slot_get(self->value_type, self->value_type_class, mem);
@@ -463,6 +473,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
463
473
  VALUE Map_clear(VALUE _self) {
464
474
  Map* self = ruby_to_Map(_self);
465
475
 
476
+ rb_check_frozen(_self);
477
+
466
478
  // Uninit and reinit the table -- this is faster than iterating and doing a
467
479
  // delete-lookup on each key.
468
480
  upb_strtable_uninit(&self->table);
@@ -483,7 +495,7 @@ VALUE Map_length(VALUE _self) {
483
495
  return ULL2NUM(upb_strtable_count(&self->table));
484
496
  }
485
497
 
486
- static VALUE Map_new_this_type(VALUE _self) {
498
+ VALUE Map_new_this_type(VALUE _self) {
487
499
  Map* self = ruby_to_Map(_self);
488
500
  VALUE new_map = Qnil;
489
501
  VALUE key_type = fieldtype_to_ruby(self->key_type);
@@ -547,7 +559,8 @@ VALUE Map_deep_copy(VALUE _self) {
547
559
  void* mem = value_memory(&v);
548
560
  upb_value dup;
549
561
  void* dup_mem = value_memory(&dup);
550
- native_slot_deep_copy(self->value_type, dup_mem, mem);
562
+ native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
563
+ mem);
551
564
 
552
565
  if (!upb_strtable_insert2(&new_self->table,
553
566
  upb_strtable_iter_key(&it),
@@ -619,7 +632,8 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
619
632
  return Qfalse;
620
633
  }
621
634
 
622
- if (!native_slot_eq(self->value_type, mem, other_mem)) {
635
+ if (!native_slot_eq(self->value_type, self->value_type_class, mem,
636
+ other_mem)) {
623
637
  // Present, but value not equal.
624
638
  return Qfalse;
625
639
  }
@@ -841,7 +855,6 @@ void Map_register(VALUE module) {
841
855
  rb_define_method(klass, "dup", Map_dup, 0);
842
856
  rb_define_method(klass, "==", Map_eq, 1);
843
857
  rb_define_method(klass, "hash", Map_hash, 0);
844
- rb_define_method(klass, "to_hash", Map_to_h, 0);
845
858
  rb_define_method(klass, "to_h", Map_to_h, 0);
846
859
  rb_define_method(klass, "inspect", Map_inspect, 0);
847
860
  rb_define_method(klass, "merge", Map_merge, 1);
@@ -60,47 +60,30 @@ rb_data_type_t Message_type = {
60
60
  VALUE Message_alloc(VALUE klass) {
61
61
  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
62
62
  Descriptor* desc = ruby_to_Descriptor(descriptor);
63
- MessageHeader* msg = (MessageHeader*)ALLOC_N(
64
- uint8_t, sizeof(MessageHeader) + desc->layout->size);
63
+ MessageHeader* msg;
65
64
  VALUE ret;
66
65
 
67
- memset(Message_data(msg), 0, desc->layout->size);
66
+ if (desc->layout == NULL) {
67
+ create_layout(desc);
68
+ }
68
69
 
69
- // We wrap first so that everything in the message object is GC-rooted in case
70
- // a collection happens during object creation in layout_init().
71
- ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
70
+ msg = (void*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
72
71
  msg->descriptor = desc;
73
- rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
74
-
75
72
  msg->unknown_fields = NULL;
73
+ memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
76
74
 
77
- layout_init(desc->layout, Message_data(msg));
75
+ ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
76
+ rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
78
77
 
79
78
  return ret;
80
79
  }
81
80
 
82
81
  static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
83
- upb_oneof_iter it;
84
- size_t case_ofs;
85
82
  uint32_t oneof_case;
86
- const upb_fielddef* first_field;
87
83
  const upb_fielddef* f;
88
84
 
89
- // If no fields in the oneof, always nil.
90
- if (upb_oneofdef_numfields(o) == 0) {
91
- return NULL;
92
- }
93
- // Grab the first field in the oneof so we can get its layout info to find the
94
- // oneof_case field.
95
- upb_oneof_begin(&it, o);
96
- assert(!upb_oneof_done(&it));
97
- first_field = upb_oneof_iter_field(&it);
98
- assert(upb_fielddef_containingoneof(first_field) != NULL);
99
-
100
- case_ofs =
101
- self->descriptor->layout->
102
- fields[upb_fielddef_index(first_field)].case_offset;
103
- oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
85
+ oneof_case =
86
+ slot_read_oneof_case(self->descriptor->layout, Message_data(self), o);
104
87
 
105
88
  if (oneof_case == ONEOF_CASE_NONE) {
106
89
  return NULL;
@@ -118,19 +101,63 @@ enum {
118
101
  METHOD_GETTER = 1,
119
102
  METHOD_SETTER = 2,
120
103
  METHOD_CLEAR = 3,
121
- METHOD_PRESENCE = 4
104
+ METHOD_PRESENCE = 4,
105
+ METHOD_ENUM_GETTER = 5,
106
+ METHOD_WRAPPER_GETTER = 6,
107
+ METHOD_WRAPPER_SETTER = 7
122
108
  };
123
109
 
124
- static int extract_method_call(VALUE method_name, MessageHeader* self,
125
- const upb_fielddef **f, const upb_oneofdef **o) {
126
- Check_Type(method_name, T_SYMBOL);
110
+ // Check if the field is a well known wrapper type
111
+ bool is_wrapper_type_field(const upb_fielddef* field) {
112
+ const upb_msgdef *m;
113
+ if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
114
+ return false;
115
+ }
116
+ m = upb_fielddef_msgsubdef(field);
117
+ switch (upb_msgdef_wellknowntype(m)) {
118
+ case UPB_WELLKNOWN_DOUBLEVALUE:
119
+ case UPB_WELLKNOWN_FLOATVALUE:
120
+ case UPB_WELLKNOWN_INT64VALUE:
121
+ case UPB_WELLKNOWN_UINT64VALUE:
122
+ case UPB_WELLKNOWN_INT32VALUE:
123
+ case UPB_WELLKNOWN_UINT32VALUE:
124
+ case UPB_WELLKNOWN_STRINGVALUE:
125
+ case UPB_WELLKNOWN_BYTESVALUE:
126
+ case UPB_WELLKNOWN_BOOLVALUE:
127
+ return true;
128
+ default:
129
+ return false;
130
+ }
131
+ }
132
+
133
+ // Get a new Ruby wrapper type and set the initial value
134
+ VALUE ruby_wrapper_type(VALUE type_class, VALUE value) {
135
+ if (value != Qnil) {
136
+ VALUE hash = rb_hash_new();
137
+ rb_hash_aset(hash, rb_str_new2("value"), value);
138
+ {
139
+ VALUE args[1] = {hash};
140
+ return rb_class_new_instance(1, args, type_class);
141
+ }
142
+ }
143
+ return Qnil;
144
+ }
127
145
 
128
- VALUE method_str = rb_id2str(SYM2ID(method_name));
129
- char* name = RSTRING_PTR(method_str);
130
- size_t name_len = RSTRING_LEN(method_str);
146
+ static int extract_method_call(VALUE method_name, MessageHeader* self,
147
+ const upb_fielddef **f, const upb_oneofdef **o) {
148
+ VALUE method_str;
149
+ char* name;
150
+ size_t name_len;
131
151
  int accessor_type;
132
152
  const upb_oneofdef* test_o;
133
153
  const upb_fielddef* test_f;
154
+ bool has_field;
155
+
156
+ Check_Type(method_name, T_SYMBOL);
157
+
158
+ method_str = rb_id2str(SYM2ID(method_name));
159
+ name = RSTRING_PTR(method_str);
160
+ name_len = RSTRING_LEN(method_str);
134
161
 
135
162
  if (name[name_len - 1] == '=') {
136
163
  accessor_type = METHOD_SETTER;
@@ -139,13 +166,13 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
139
166
  // we don't strip the prefix.
140
167
  } else if (strncmp("clear_", name, 6) == 0 &&
141
168
  !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
142
- &test_f, &test_o)) {
169
+ &test_f, &test_o)) {
143
170
  accessor_type = METHOD_CLEAR;
144
171
  name = name + 6;
145
172
  name_len = name_len - 6;
146
173
  } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
147
174
  !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
148
- &test_f, &test_o)) {
175
+ &test_f, &test_o)) {
149
176
  accessor_type = METHOD_PRESENCE;
150
177
  name = name + 4;
151
178
  name_len = name_len - 5;
@@ -153,9 +180,62 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
153
180
  accessor_type = METHOD_GETTER;
154
181
  }
155
182
 
183
+ has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
184
+ &test_f, &test_o);
185
+
186
+ // Look for wrapper type accessor of the form <field_name>_as_value
187
+ if (!has_field &&
188
+ (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
189
+ name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
190
+ const upb_oneofdef* test_o_wrapper;
191
+ const upb_fielddef* test_f_wrapper;
192
+ char wrapper_field_name[name_len - 8];
193
+
194
+ // Find the field name
195
+ strncpy(wrapper_field_name, name, name_len - 9);
196
+ wrapper_field_name[name_len - 9] = '\0';
197
+
198
+ // Check if field exists and is a wrapper type
199
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
200
+ name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
201
+ is_wrapper_type_field(test_f_wrapper)) {
202
+ // It does exist!
203
+ has_field = true;
204
+ if (accessor_type == METHOD_SETTER) {
205
+ accessor_type = METHOD_WRAPPER_SETTER;
206
+ } else {
207
+ accessor_type = METHOD_WRAPPER_GETTER;
208
+ }
209
+ test_o = test_o_wrapper;
210
+ test_f = test_f_wrapper;
211
+ }
212
+ }
213
+
214
+ // Look for enum accessor of the form <enum_name>_const
215
+ if (!has_field && accessor_type == METHOD_GETTER &&
216
+ name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
217
+ const upb_oneofdef* test_o_enum;
218
+ const upb_fielddef* test_f_enum;
219
+ char enum_name[name_len - 5];
220
+
221
+ // Find enum field name
222
+ strncpy(enum_name, name, name_len - 6);
223
+ enum_name[name_len - 6] = '\0';
224
+
225
+ // Check if enum field exists
226
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
227
+ &test_f_enum, &test_o_enum) &&
228
+ upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
229
+ // It does exist!
230
+ has_field = true;
231
+ accessor_type = METHOD_ENUM_GETTER;
232
+ test_o = test_o_enum;
233
+ test_f = test_f_enum;
234
+ }
235
+ }
236
+
156
237
  // Verify the name corresponds to a oneof or field in this message.
157
- if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
158
- &test_f, &test_o)) {
238
+ if (!has_field) {
159
239
  return METHOD_UNKNOWN;
160
240
  }
161
241
 
@@ -203,41 +283,44 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
203
283
  MessageHeader* self;
204
284
  const upb_oneofdef* o;
205
285
  const upb_fielddef* f;
286
+ int accessor_type;
206
287
 
207
288
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
208
289
  if (argc < 1) {
209
290
  rb_raise(rb_eArgError, "Expected method name as first argument.");
210
291
  }
211
292
 
212
- int accessor_type = extract_method_call(argv[0], self, &f, &o);
293
+ accessor_type = extract_method_call(argv[0], self, &f, &o);
213
294
  if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
214
295
  return rb_call_super(argc, argv);
215
- } else if (accessor_type == METHOD_SETTER) {
296
+ } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
216
297
  if (argc != 2) {
217
298
  rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
218
299
  }
300
+ rb_check_frozen(_self);
219
301
  } else if (argc != 1) {
220
302
  rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
221
303
  }
222
304
 
223
305
  // Return which of the oneof fields are set
224
306
  if (o != NULL) {
307
+ const upb_fielddef* oneof_field = which_oneof_field(self, o);
308
+
225
309
  if (accessor_type == METHOD_SETTER) {
226
310
  rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
227
311
  }
228
312
 
229
- const upb_fielddef* oneof_field = which_oneof_field(self, o);
230
313
  if (accessor_type == METHOD_PRESENCE) {
231
314
  return oneof_field == NULL ? Qfalse : Qtrue;
232
315
  } else if (accessor_type == METHOD_CLEAR) {
233
316
  if (oneof_field != NULL) {
234
- layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
317
+ layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
235
318
  }
236
319
  return Qnil;
237
320
  } else {
238
321
  // METHOD_ACCESSOR
239
322
  return oneof_field == NULL ? Qnil :
240
- ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
323
+ ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
241
324
  }
242
325
  // Otherwise we're operating on a single proto field
243
326
  } else if (accessor_type == METHOD_SETTER) {
@@ -248,6 +331,41 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
248
331
  return Qnil;
249
332
  } else if (accessor_type == METHOD_PRESENCE) {
250
333
  return layout_has(self->descriptor->layout, Message_data(self), f);
334
+ } else if (accessor_type == METHOD_WRAPPER_GETTER) {
335
+ VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
336
+ switch (TYPE(value)) {
337
+ case T_DATA:
338
+ return rb_funcall(value, rb_intern("value"), 0);
339
+ case T_NIL:
340
+ return Qnil;
341
+ default:
342
+ return value;
343
+ }
344
+ } else if (accessor_type == METHOD_WRAPPER_SETTER) {
345
+ VALUE wrapper = ruby_wrapper_type(
346
+ field_type_class(self->descriptor->layout, f), argv[1]);
347
+ layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
348
+ return Qnil;
349
+ } else if (accessor_type == METHOD_ENUM_GETTER) {
350
+ VALUE enum_type = field_type_class(self->descriptor->layout, f);
351
+ VALUE method = rb_intern("const_get");
352
+ VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
353
+
354
+ // Map repeated fields to a new type with ints
355
+ if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
356
+ int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
357
+ int i;
358
+ VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
359
+ VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
360
+ for (i = 0; i < array_size; i++) {
361
+ VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
362
+ rb_intern("at"), 1, INT2NUM(i)));
363
+ rb_funcall(array, rb_intern("push"), 1, entry);
364
+ }
365
+ return array;
366
+ }
367
+ // Convert the value for singular fields
368
+ return rb_funcall(enum_type, method, 1, raw_value);
251
369
  } else {
252
370
  return layout_get(self->descriptor->layout, Message_data(self), f);
253
371
  }
@@ -258,13 +376,14 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
258
376
  MessageHeader* self;
259
377
  const upb_oneofdef* o;
260
378
  const upb_fielddef* f;
379
+ int accessor_type;
261
380
 
262
381
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
263
382
  if (argc < 1) {
264
383
  rb_raise(rb_eArgError, "Expected method name as first argument.");
265
384
  }
266
385
 
267
- int accessor_type = extract_method_call(argv[0], self, &f, &o);
386
+ accessor_type = extract_method_call(argv[0], self, &f, &o);
268
387
  if (accessor_type == METHOD_UNKNOWN) {
269
388
  return rb_call_super(argc, argv);
270
389
  } else if (o != NULL) {
@@ -274,15 +393,10 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
274
393
  }
275
394
  }
276
395
 
277
- VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
278
- const upb_def *d = upb_fielddef_subdef(f);
279
- assert(d != NULL);
280
-
281
- VALUE descriptor = get_def_obj(d);
282
- VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
283
-
396
+ VALUE create_submsg_from_hash(const MessageLayout* layout,
397
+ const upb_fielddef* f, VALUE hash) {
284
398
  VALUE args[1] = { hash };
285
- return rb_class_new_instance(1, args, msgclass);
399
+ return rb_class_new_instance(1, args, field_type_class(layout, f));
286
400
  }
287
401
 
288
402
  int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
@@ -315,29 +429,32 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
315
429
 
316
430
  if (TYPE(val) != T_HASH) {
317
431
  rb_raise(rb_eArgError,
318
- "Expected Hash object as initializer value for map field '%s'.", name);
432
+ "Expected Hash object as initializer value for map field '%s' (given %s).",
433
+ name, rb_class2name(CLASS_OF(val)));
319
434
  }
320
435
  map = layout_get(self->descriptor->layout, Message_data(self), f);
321
436
  Map_merge_into_self(map, val);
322
437
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
323
438
  VALUE ary;
439
+ int i;
324
440
 
325
441
  if (TYPE(val) != T_ARRAY) {
326
442
  rb_raise(rb_eArgError,
327
- "Expected array as initializer value for repeated field '%s'.", name);
443
+ "Expected array as initializer value for repeated field '%s' (given %s).",
444
+ name, rb_class2name(CLASS_OF(val)));
328
445
  }
329
446
  ary = layout_get(self->descriptor->layout, Message_data(self), f);
330
- for (int i = 0; i < RARRAY_LEN(val); i++) {
447
+ for (i = 0; i < RARRAY_LEN(val); i++) {
331
448
  VALUE entry = rb_ary_entry(val, i);
332
449
  if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
333
- entry = create_submsg_from_hash(f, entry);
450
+ entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
334
451
  }
335
452
 
336
453
  RepeatedField_push(ary, entry);
337
454
  }
338
455
  } else {
339
456
  if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
340
- val = create_submsg_from_hash(f, val);
457
+ val = create_submsg_from_hash(self->descriptor->layout, f, val);
341
458
  }
342
459
 
343
460
  layout_set(self->descriptor->layout, Message_data(self), f, val);
@@ -358,7 +475,11 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
358
475
  * Message class are provided on each concrete message class.
359
476
  */
360
477
  VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
478
+ MessageHeader* self;
361
479
  VALUE hash_args;
480
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
481
+
482
+ layout_init(self->descriptor->layout, Message_data(self));
362
483
 
363
484
  if (argc == 0) {
364
485
  return Qnil;
@@ -494,17 +615,18 @@ VALUE Message_to_h(VALUE _self) {
494
615
  !upb_msg_field_done(&it);
495
616
  upb_msg_field_next(&it)) {
496
617
  const upb_fielddef* field = upb_msg_iter_field(&it);
618
+ VALUE msg_value;
619
+ VALUE msg_key;
497
620
 
498
621
  // For proto2, do not include fields which are not set.
499
622
  if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
500
- field_contains_hasbit(self->descriptor->layout, field) &&
501
- !layout_has(self->descriptor->layout, Message_data(self), field)) {
623
+ field_contains_hasbit(self->descriptor->layout, field) &&
624
+ !layout_has(self->descriptor->layout, Message_data(self), field)) {
502
625
  continue;
503
626
  }
504
627
 
505
- VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
506
- field);
507
- VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
628
+ msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
629
+ msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
508
630
  if (is_map_field(field)) {
509
631
  msg_value = Map_to_h(msg_value);
510
632
  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
@@ -515,7 +637,8 @@ VALUE Message_to_h(VALUE _self) {
515
637
  }
516
638
 
517
639
  if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
518
- for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
640
+ int i;
641
+ for (i = 0; i < RARRAY_LEN(msg_value); i++) {
519
642
  VALUE elem = rb_ary_entry(msg_value, i);
520
643
  rb_ary_store(msg_value, i, Message_to_h(elem));
521
644
  }
@@ -582,17 +705,11 @@ VALUE Message_descriptor(VALUE klass) {
582
705
  return rb_ivar_get(klass, descriptor_instancevar_interned);
583
706
  }
584
707
 
585
- VALUE build_class_from_descriptor(Descriptor* desc) {
708
+ VALUE build_class_from_descriptor(VALUE descriptor) {
709
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
586
710
  const char *name;
587
711
  VALUE klass;
588
712
 
589
- if (desc->layout == NULL) {
590
- desc->layout = create_layout(desc->msgdef);
591
- }
592
- if (desc->fill_method == NULL) {
593
- desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
594
- }
595
-
596
713
  name = upb_msgdef_fullname(desc->msgdef);
597
714
  if (name == NULL) {
598
715
  rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
@@ -603,8 +720,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
603
720
  // their own toplevel constant class name.
604
721
  rb_intern("Message"),
605
722
  rb_cObject);
606
- rb_ivar_set(klass, descriptor_instancevar_interned,
607
- get_def_obj(desc->msgdef));
723
+ rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
608
724
  rb_define_alloc_func(klass, Message_alloc);
609
725
  rb_require("google/protobuf/message_exts");
610
726
  rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
@@ -620,10 +736,11 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
620
736
  // Also define #clone so that we don't inherit Object#clone.
621
737
  rb_define_method(klass, "clone", Message_dup, 0);
622
738
  rb_define_method(klass, "==", Message_eq, 1);
739
+ rb_define_method(klass, "eql?", Message_eq, 1);
623
740
  rb_define_method(klass, "hash", Message_hash, 0);
624
741
  rb_define_method(klass, "to_h", Message_to_h, 0);
625
- rb_define_method(klass, "to_hash", Message_to_h, 0);
626
742
  rb_define_method(klass, "inspect", Message_inspect, 0);
743
+ rb_define_method(klass, "to_s", Message_inspect, 0);
627
744
  rb_define_method(klass, "[]", Message_index, 1);
628
745
  rb_define_method(klass, "[]=", Message_index_set, 2);
629
746
  rb_define_singleton_method(klass, "decode", Message_decode, 1);
@@ -687,7 +804,8 @@ VALUE enum_descriptor(VALUE self) {
687
804
  return rb_ivar_get(self, descriptor_instancevar_interned);
688
805
  }
689
806
 
690
- VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
807
+ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
808
+ EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
691
809
  VALUE mod = rb_define_module_id(
692
810
  rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
693
811
 
@@ -708,8 +826,7 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
708
826
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
709
827
  rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
710
828
  rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
711
- rb_ivar_set(mod, descriptor_instancevar_interned,
712
- get_def_obj(enumdesc->enumdef));
829
+ rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
713
830
 
714
831
  return mod;
715
832
  }
@@ -30,25 +30,35 @@
30
30
 
31
31
  #include "protobuf.h"
32
32
 
33
- // -----------------------------------------------------------------------------
34
- // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
35
- // instances.
36
- // -----------------------------------------------------------------------------
37
-
38
- // This is a hash table from def objects (encoded by converting pointers to
39
- // Ruby integers) to MessageDef/EnumDef instances (as Ruby values).
40
- VALUE upb_def_to_ruby_obj_map;
41
-
42
33
  VALUE cError;
43
34
  VALUE cParseError;
44
35
  VALUE cTypeError;
36
+ VALUE c_only_cookie = Qnil;
45
37
 
46
- void add_def_obj(const void* def, VALUE value) {
47
- rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
38
+ static VALUE cached_empty_string = Qnil;
39
+ static VALUE cached_empty_bytes = Qnil;
40
+
41
+ static VALUE create_frozen_string(const char* str, size_t size, bool binary) {
42
+ VALUE str_rb = rb_str_new(str, size);
43
+
44
+ rb_enc_associate(str_rb,
45
+ binary ? kRubyString8bitEncoding : kRubyStringUtf8Encoding);
46
+ rb_obj_freeze(str_rb);
47
+ return str_rb;
48
48
  }
49
49
 
50
- VALUE get_def_obj(const void* def) {
51
- return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def));
50
+ VALUE get_frozen_string(const char* str, size_t size, bool binary) {
51
+ if (size == 0) {
52
+ return binary ? cached_empty_bytes : cached_empty_string;
53
+ } else {
54
+ // It is harder to memoize non-empty strings. The obvious approach would be
55
+ // to use a Ruby hash keyed by string as memo table, but looking up in such a table
56
+ // requires constructing a string (the very thing we're trying to avoid).
57
+ //
58
+ // Since few fields have defaults, we will just optimize the empty string
59
+ // case for now.
60
+ return create_frozen_string(str, size, binary);
61
+ }
52
62
  }
53
63
 
54
64
  // -----------------------------------------------------------------------------
@@ -116,6 +126,11 @@ void Init_protobuf_c() {
116
126
  kRubyStringASCIIEncoding = rb_usascii_encoding();
117
127
  kRubyString8bitEncoding = rb_ascii8bit_encoding();
118
128
 
119
- rb_gc_register_address(&upb_def_to_ruby_obj_map);
120
- upb_def_to_ruby_obj_map = rb_hash_new();
129
+ rb_gc_register_address(&c_only_cookie);
130
+ c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
131
+
132
+ rb_gc_register_address(&cached_empty_string);
133
+ rb_gc_register_address(&cached_empty_bytes);
134
+ cached_empty_string = create_frozen_string("", 0, false);
135
+ cached_empty_bytes = create_frozen_string("", 0, true);
121
136
  }