google-protobuf 3.8.0 → 3.13.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);
@@ -97,11 +100,11 @@ static VALUE table_key(Map* self, VALUE key,
97
100
  return key;
98
101
  }
99
102
 
100
- static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
103
+ static VALUE table_key_to_ruby(Map* self, upb_strview key) {
101
104
  switch (self->key_type) {
102
105
  case UPB_TYPE_BYTES:
103
106
  case UPB_TYPE_STRING: {
104
- VALUE ret = rb_str_new(buf, length);
107
+ VALUE ret = rb_str_new(key.data, key.size);
105
108
  rb_enc_associate(ret,
106
109
  (self->key_type == UPB_TYPE_BYTES) ?
107
110
  kRubyString8bitEncoding : kRubyStringUtf8Encoding);
@@ -113,7 +116,7 @@ static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
113
116
  case UPB_TYPE_INT64:
114
117
  case UPB_TYPE_UINT32:
115
118
  case UPB_TYPE_UINT64:
116
- return native_slot_get(self->key_type, Qnil, buf);
119
+ return native_slot_get(self->key_type, Qnil, key.data);
117
120
 
118
121
  default:
119
122
  assert(false);
@@ -286,9 +289,7 @@ VALUE Map_each(VALUE _self) {
286
289
  for (upb_strtable_begin(&it, &self->table);
287
290
  !upb_strtable_done(&it);
288
291
  upb_strtable_next(&it)) {
289
-
290
- VALUE key = table_key_to_ruby(
291
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
292
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
292
293
 
293
294
  upb_value v = upb_strtable_iter_value(&it);
294
295
  void* mem = value_memory(&v);
@@ -316,9 +317,7 @@ VALUE Map_keys(VALUE _self) {
316
317
  for (upb_strtable_begin(&it, &self->table);
317
318
  !upb_strtable_done(&it);
318
319
  upb_strtable_next(&it)) {
319
-
320
- VALUE key = table_key_to_ruby(
321
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
320
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
322
321
 
323
322
  rb_ary_push(ret, key);
324
323
  }
@@ -386,10 +385,7 @@ VALUE Map_index(VALUE _self, VALUE key) {
386
385
  * was just inserted.
387
386
  */
388
387
  VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
389
- rb_check_frozen(_self);
390
-
391
388
  Map* self = ruby_to_Map(_self);
392
-
393
389
  char keybuf[TABLE_KEY_BUF_LENGTH];
394
390
  const char* keyval = NULL;
395
391
  size_t length = 0;
@@ -397,6 +393,13 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
397
393
  void* mem;
398
394
  key = table_key(self, key, keybuf, &keyval, &length);
399
395
 
396
+ rb_check_frozen(_self);
397
+
398
+ if (TYPE(value) == T_HASH) {
399
+ VALUE args[1] = { value };
400
+ value = rb_class_new_instance(1, args, self->value_type_class);
401
+ }
402
+
400
403
  mem = value_memory(&v);
401
404
  native_slot_set("", self->value_type, self->value_type_class, mem, value);
402
405
 
@@ -440,16 +443,15 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
440
443
  * nil if none was present. Throws an exception if the key is of the wrong type.
441
444
  */
442
445
  VALUE Map_delete(VALUE _self, VALUE key) {
443
- rb_check_frozen(_self);
444
-
445
446
  Map* self = ruby_to_Map(_self);
446
-
447
447
  char keybuf[TABLE_KEY_BUF_LENGTH];
448
448
  const char* keyval = NULL;
449
449
  size_t length = 0;
450
450
  upb_value v;
451
451
  key = table_key(self, key, keybuf, &keyval, &length);
452
452
 
453
+ rb_check_frozen(_self);
454
+
453
455
  if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
454
456
  void* mem = value_memory(&v);
455
457
  return native_slot_get(self->value_type, self->value_type_class, mem);
@@ -465,10 +467,10 @@ VALUE Map_delete(VALUE _self, VALUE key) {
465
467
  * Removes all entries from the map.
466
468
  */
467
469
  VALUE Map_clear(VALUE _self) {
468
- rb_check_frozen(_self);
469
-
470
470
  Map* self = ruby_to_Map(_self);
471
471
 
472
+ rb_check_frozen(_self);
473
+
472
474
  // Uninit and reinit the table -- this is faster than iterating and doing a
473
475
  // delete-lookup on each key.
474
476
  upb_strtable_uninit(&self->table);
@@ -489,7 +491,7 @@ VALUE Map_length(VALUE _self) {
489
491
  return ULL2NUM(upb_strtable_count(&self->table));
490
492
  }
491
493
 
492
- static VALUE Map_new_this_type(VALUE _self) {
494
+ VALUE Map_new_this_type(VALUE _self) {
493
495
  Map* self = ruby_to_Map(_self);
494
496
  VALUE new_map = Qnil;
495
497
  VALUE key_type = fieldtype_to_ruby(self->key_type);
@@ -520,17 +522,14 @@ VALUE Map_dup(VALUE _self) {
520
522
  for (upb_strtable_begin(&it, &self->table);
521
523
  !upb_strtable_done(&it);
522
524
  upb_strtable_next(&it)) {
523
-
525
+ upb_strview k = upb_strtable_iter_key(&it);
524
526
  upb_value v = upb_strtable_iter_value(&it);
525
527
  void* mem = value_memory(&v);
526
528
  upb_value dup;
527
529
  void* dup_mem = value_memory(&dup);
528
530
  native_slot_dup(self->value_type, dup_mem, mem);
529
531
 
530
- if (!upb_strtable_insert2(&new_self->table,
531
- upb_strtable_iter_key(&it),
532
- upb_strtable_iter_keylength(&it),
533
- dup)) {
532
+ if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
534
533
  rb_raise(rb_eRuntimeError, "Error inserting value into new table");
535
534
  }
536
535
  }
@@ -548,17 +547,15 @@ VALUE Map_deep_copy(VALUE _self) {
548
547
  for (upb_strtable_begin(&it, &self->table);
549
548
  !upb_strtable_done(&it);
550
549
  upb_strtable_next(&it)) {
551
-
550
+ upb_strview k = upb_strtable_iter_key(&it);
552
551
  upb_value v = upb_strtable_iter_value(&it);
553
552
  void* mem = value_memory(&v);
554
553
  upb_value dup;
555
554
  void* dup_mem = value_memory(&dup);
556
- native_slot_deep_copy(self->value_type, dup_mem, mem);
555
+ native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
556
+ mem);
557
557
 
558
- if (!upb_strtable_insert2(&new_self->table,
559
- upb_strtable_iter_key(&it),
560
- upb_strtable_iter_keylength(&it),
561
- dup)) {
558
+ if (!upb_strtable_insert2(&new_self->table, k.data, k.size, dup)) {
562
559
  rb_raise(rb_eRuntimeError, "Error inserting value into new table");
563
560
  }
564
561
  }
@@ -611,21 +608,19 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
611
608
  for (upb_strtable_begin(&it, &self->table);
612
609
  !upb_strtable_done(&it);
613
610
  upb_strtable_next(&it)) {
614
-
611
+ upb_strview k = upb_strtable_iter_key(&it);
615
612
  upb_value v = upb_strtable_iter_value(&it);
616
613
  void* mem = value_memory(&v);
617
614
  upb_value other_v;
618
615
  void* other_mem = value_memory(&other_v);
619
616
 
620
- if (!upb_strtable_lookup2(&other->table,
621
- upb_strtable_iter_key(&it),
622
- upb_strtable_iter_keylength(&it),
623
- &other_v)) {
617
+ if (!upb_strtable_lookup2(&other->table, k.data, k.size, &other_v)) {
624
618
  // Not present in other map.
625
619
  return Qfalse;
626
620
  }
627
621
 
628
- if (!native_slot_eq(self->value_type, mem, other_mem)) {
622
+ if (!native_slot_eq(self->value_type, self->value_type_class, mem,
623
+ other_mem)) {
629
624
  // Present, but value not equal.
630
625
  return Qfalse;
631
626
  }
@@ -647,11 +642,9 @@ VALUE Map_hash(VALUE _self) {
647
642
  VALUE hash_sym = rb_intern("hash");
648
643
 
649
644
  upb_strtable_iter it;
650
- for (upb_strtable_begin(&it, &self->table);
651
- !upb_strtable_done(&it);
645
+ for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
652
646
  upb_strtable_next(&it)) {
653
- VALUE key = table_key_to_ruby(
654
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
647
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
655
648
 
656
649
  upb_value v = upb_strtable_iter_value(&it);
657
650
  void* mem = value_memory(&v);
@@ -679,8 +672,7 @@ VALUE Map_to_h(VALUE _self) {
679
672
  for (upb_strtable_begin(&it, &self->table);
680
673
  !upb_strtable_done(&it);
681
674
  upb_strtable_next(&it)) {
682
- VALUE key = table_key_to_ruby(
683
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
675
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
684
676
  upb_value v = upb_strtable_iter_value(&it);
685
677
  void* mem = value_memory(&v);
686
678
  VALUE value = native_slot_get(self->value_type,
@@ -712,11 +704,9 @@ VALUE Map_inspect(VALUE _self) {
712
704
  VALUE inspect_sym = rb_intern("inspect");
713
705
 
714
706
  upb_strtable_iter it;
715
- for (upb_strtable_begin(&it, &self->table);
716
- !upb_strtable_done(&it);
707
+ for (upb_strtable_begin(&it, &self->table); !upb_strtable_done(&it);
717
708
  upb_strtable_next(&it)) {
718
- VALUE key = table_key_to_ruby(
719
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
709
+ VALUE key = table_key_to_ruby(self, upb_strtable_iter_key(&it));
720
710
 
721
711
  upb_value v = upb_strtable_iter_value(&it);
722
712
  void* mem = value_memory(&v);
@@ -777,20 +767,15 @@ VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
777
767
  for (upb_strtable_begin(&it, &other->table);
778
768
  !upb_strtable_done(&it);
779
769
  upb_strtable_next(&it)) {
770
+ upb_strview k = upb_strtable_iter_key(&it);
780
771
 
781
772
  // Replace any existing value by issuing a 'remove' operation first.
782
773
  upb_value v;
783
774
  upb_value oldv;
784
- upb_strtable_remove2(&self->table,
785
- upb_strtable_iter_key(&it),
786
- upb_strtable_iter_keylength(&it),
787
- &oldv);
775
+ upb_strtable_remove2(&self->table, k.data, k.size, &oldv);
788
776
 
789
777
  v = upb_strtable_iter_value(&it);
790
- upb_strtable_insert2(&self->table,
791
- upb_strtable_iter_key(&it),
792
- upb_strtable_iter_keylength(&it),
793
- v);
778
+ upb_strtable_insert2(&self->table, k.data, k.size, v);
794
779
  }
795
780
  } else {
796
781
  rb_raise(rb_eArgError, "Unknown type merging into Map");
@@ -814,10 +799,7 @@ bool Map_done(Map_iter* iter) {
814
799
  }
815
800
 
816
801
  VALUE Map_iter_key(Map_iter* iter) {
817
- return table_key_to_ruby(
818
- iter->self,
819
- upb_strtable_iter_key(&iter->it),
820
- upb_strtable_iter_keylength(&iter->it));
802
+ return table_key_to_ruby(iter->self, upb_strtable_iter_key(&iter->it));
821
803
  }
822
804
 
823
805
  VALUE Map_iter_value(Map_iter* iter) {
@@ -847,7 +829,6 @@ void Map_register(VALUE module) {
847
829
  rb_define_method(klass, "dup", Map_dup, 0);
848
830
  rb_define_method(klass, "==", Map_eq, 1);
849
831
  rb_define_method(klass, "hash", Map_hash, 0);
850
- rb_define_method(klass, "to_hash", Map_to_h, 0);
851
832
  rb_define_method(klass, "to_h", Map_to_h, 0);
852
833
  rb_define_method(klass, "inspect", Map_inspect, 0);
853
834
  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;
@@ -125,41 +108,56 @@ enum {
125
108
  };
126
109
 
127
110
  // Check if the field is a well known wrapper type
128
- static bool is_wrapper_type_field(const upb_fielddef* field) {
129
- char* field_type_name = rb_class2name(field_type_class(field));
130
-
131
- return strcmp(field_type_name, "Google::Protobuf::DoubleValue") == 0 ||
132
- strcmp(field_type_name, "Google::Protobuf::FloatValue") == 0 ||
133
- strcmp(field_type_name, "Google::Protobuf::Int32Value") == 0 ||
134
- strcmp(field_type_name, "Google::Protobuf::Int64Value") == 0 ||
135
- strcmp(field_type_name, "Google::Protobuf::UInt32Value") == 0 ||
136
- strcmp(field_type_name, "Google::Protobuf::UInt64Value") == 0 ||
137
- strcmp(field_type_name, "Google::Protobuf::BoolValue") == 0 ||
138
- strcmp(field_type_name, "Google::Protobuf::StringValue") == 0 ||
139
- strcmp(field_type_name, "Google::Protobuf::BytesValue") == 0;
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
+ }
140
131
  }
141
132
 
142
133
  // Get a new Ruby wrapper type and set the initial value
143
- static VALUE ruby_wrapper_type(const upb_fielddef* field, const VALUE* value) {
144
- if (is_wrapper_type_field(field) && value != Qnil) {
134
+ VALUE ruby_wrapper_type(VALUE type_class, VALUE value) {
135
+ if (value != Qnil) {
145
136
  VALUE hash = rb_hash_new();
146
137
  rb_hash_aset(hash, rb_str_new2("value"), value);
147
- VALUE args[1] = { hash };
148
- return rb_class_new_instance(1, args, field_type_class(field));
138
+ {
139
+ VALUE args[1] = {hash};
140
+ return rb_class_new_instance(1, args, type_class);
141
+ }
149
142
  }
150
143
  return Qnil;
151
144
  }
152
145
 
153
146
  static int extract_method_call(VALUE method_name, MessageHeader* self,
154
- const upb_fielddef **f, const upb_oneofdef **o) {
155
- Check_Type(method_name, T_SYMBOL);
156
-
157
- VALUE method_str = rb_id2str(SYM2ID(method_name));
158
- char* name = RSTRING_PTR(method_str);
159
- size_t name_len = RSTRING_LEN(method_str);
147
+ const upb_fielddef **f, const upb_oneofdef **o) {
148
+ VALUE method_str;
149
+ char* name;
150
+ size_t name_len;
160
151
  int accessor_type;
161
152
  const upb_oneofdef* test_o;
162
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);
163
161
 
164
162
  if (name[name_len - 1] == '=') {
165
163
  accessor_type = METHOD_SETTER;
@@ -168,13 +166,13 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
168
166
  // we don't strip the prefix.
169
167
  } else if (strncmp("clear_", name, 6) == 0 &&
170
168
  !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
171
- &test_f, &test_o)) {
169
+ &test_f, &test_o)) {
172
170
  accessor_type = METHOD_CLEAR;
173
171
  name = name + 6;
174
172
  name_len = name_len - 6;
175
173
  } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
176
174
  !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
177
- &test_f, &test_o)) {
175
+ &test_f, &test_o)) {
178
176
  accessor_type = METHOD_PRESENCE;
179
177
  name = name + 4;
180
178
  name_len = name_len - 5;
@@ -182,24 +180,24 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
182
180
  accessor_type = METHOD_GETTER;
183
181
  }
184
182
 
185
- bool has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
186
- &test_f, &test_o);
183
+ has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
184
+ &test_f, &test_o);
187
185
 
188
186
  // Look for wrapper type accessor of the form <field_name>_as_value
189
187
  if (!has_field &&
190
188
  (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
191
189
  name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
192
- // Find the field name
190
+ const upb_oneofdef* test_o_wrapper;
191
+ const upb_fielddef* test_f_wrapper;
193
192
  char wrapper_field_name[name_len - 8];
193
+
194
+ // Find the field name
194
195
  strncpy(wrapper_field_name, name, name_len - 9);
195
- wrapper_field_name[name_len - 7] = '\0';
196
+ wrapper_field_name[name_len - 9] = '\0';
196
197
 
197
198
  // Check if field exists and is a wrapper type
198
- const upb_oneofdef* test_o_wrapper;
199
- const upb_fielddef* test_f_wrapper;
200
- if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name, name_len - 9,
201
- &test_f_wrapper, &test_o_wrapper) &&
202
- upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
199
+ if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
200
+ name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
203
201
  is_wrapper_type_field(test_f_wrapper)) {
204
202
  // It does exist!
205
203
  has_field = true;
@@ -216,17 +214,17 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
216
214
  // Look for enum accessor of the form <enum_name>_const
217
215
  if (!has_field && accessor_type == METHOD_GETTER &&
218
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];
219
220
 
220
221
  // Find enum field name
221
- char enum_name[name_len - 5];
222
222
  strncpy(enum_name, name, name_len - 6);
223
- enum_name[name_len - 4] = '\0';
223
+ enum_name[name_len - 6] = '\0';
224
224
 
225
225
  // Check if enum field exists
226
- const upb_oneofdef* test_o_enum;
227
- const upb_fielddef* test_f_enum;
228
226
  if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
229
- &test_f_enum, &test_o_enum) &&
227
+ &test_f_enum, &test_o_enum) &&
230
228
  upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
231
229
  // It does exist!
232
230
  has_field = true;
@@ -244,9 +242,14 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
244
242
  // Method calls like 'has_foo?' are not allowed if field "foo" does not have
245
243
  // a hasbit (e.g. repeated fields or non-message type fields for proto3
246
244
  // syntax).
247
- if (accessor_type == METHOD_PRESENCE && test_f != NULL &&
248
- !upb_fielddef_haspresence(test_f)) {
249
- return METHOD_UNKNOWN;
245
+ if (accessor_type == METHOD_PRESENCE && test_f != NULL) {
246
+ if (!upb_fielddef_haspresence(test_f)) return METHOD_UNKNOWN;
247
+
248
+ // TODO(haberman): remove this case, allow for proto3 oneofs.
249
+ if (upb_fielddef_realcontainingoneof(test_f) &&
250
+ upb_filedef_syntax(upb_fielddef_file(test_f)) == UPB_SYNTAX_PROTO3) {
251
+ return METHOD_UNKNOWN;
252
+ }
250
253
  }
251
254
 
252
255
  *o = test_o;
@@ -285,13 +288,14 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
285
288
  MessageHeader* self;
286
289
  const upb_oneofdef* o;
287
290
  const upb_fielddef* f;
291
+ int accessor_type;
288
292
 
289
293
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
290
294
  if (argc < 1) {
291
295
  rb_raise(rb_eArgError, "Expected method name as first argument.");
292
296
  }
293
297
 
294
- int accessor_type = extract_method_call(argv[0], self, &f, &o);
298
+ accessor_type = extract_method_call(argv[0], self, &f, &o);
295
299
  if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
296
300
  return rb_call_super(argc, argv);
297
301
  } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
@@ -305,11 +309,12 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
305
309
 
306
310
  // Return which of the oneof fields are set
307
311
  if (o != NULL) {
312
+ const upb_fielddef* oneof_field = which_oneof_field(self, o);
313
+
308
314
  if (accessor_type == METHOD_SETTER) {
309
315
  rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
310
316
  }
311
317
 
312
- const upb_fielddef* oneof_field = which_oneof_field(self, o);
313
318
  if (accessor_type == METHOD_PRESENCE) {
314
319
  return oneof_field == NULL ? Qfalse : Qtrue;
315
320
  } else if (accessor_type == METHOD_CLEAR) {
@@ -333,25 +338,31 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
333
338
  return layout_has(self->descriptor->layout, Message_data(self), f);
334
339
  } else if (accessor_type == METHOD_WRAPPER_GETTER) {
335
340
  VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
336
- if (value != Qnil) {
337
- value = rb_funcall(value, rb_intern("value"), 0);
341
+ switch (TYPE(value)) {
342
+ case T_DATA:
343
+ return rb_funcall(value, rb_intern("value"), 0);
344
+ case T_NIL:
345
+ return Qnil;
346
+ default:
347
+ return value;
338
348
  }
339
- return value;
340
349
  } else if (accessor_type == METHOD_WRAPPER_SETTER) {
341
- VALUE wrapper = ruby_wrapper_type(f, argv[1]);
350
+ VALUE wrapper = ruby_wrapper_type(
351
+ field_type_class(self->descriptor->layout, f), argv[1]);
342
352
  layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
343
353
  return Qnil;
344
354
  } else if (accessor_type == METHOD_ENUM_GETTER) {
345
- VALUE enum_type = field_type_class(f);
355
+ VALUE enum_type = field_type_class(self->descriptor->layout, f);
346
356
  VALUE method = rb_intern("const_get");
347
357
  VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
348
358
 
349
359
  // Map repeated fields to a new type with ints
350
360
  if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
351
361
  int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
362
+ int i;
352
363
  VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
353
364
  VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
354
- for (int i = 0; i < array_size; i++) {
365
+ for (i = 0; i < array_size; i++) {
355
366
  VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
356
367
  rb_intern("at"), 1, INT2NUM(i)));
357
368
  rb_funcall(array, rb_intern("push"), 1, entry);
@@ -370,13 +381,14 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
370
381
  MessageHeader* self;
371
382
  const upb_oneofdef* o;
372
383
  const upb_fielddef* f;
384
+ int accessor_type;
373
385
 
374
386
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
375
387
  if (argc < 1) {
376
388
  rb_raise(rb_eArgError, "Expected method name as first argument.");
377
389
  }
378
390
 
379
- int accessor_type = extract_method_call(argv[0], self, &f, &o);
391
+ accessor_type = extract_method_call(argv[0], self, &f, &o);
380
392
  if (accessor_type == METHOD_UNKNOWN) {
381
393
  return rb_call_super(argc, argv);
382
394
  } else if (o != NULL) {
@@ -386,15 +398,10 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
386
398
  }
387
399
  }
388
400
 
389
- VALUE create_submsg_from_hash(const upb_fielddef *f, VALUE hash) {
390
- const upb_def *d = upb_fielddef_subdef(f);
391
- assert(d != NULL);
392
-
393
- VALUE descriptor = get_def_obj(d);
394
- VALUE msgclass = rb_funcall(descriptor, rb_intern("msgclass"), 0, NULL);
395
-
401
+ VALUE create_submsg_from_hash(const MessageLayout* layout,
402
+ const upb_fielddef* f, VALUE hash) {
396
403
  VALUE args[1] = { hash };
397
- return rb_class_new_instance(1, args, msgclass);
404
+ return rb_class_new_instance(1, args, field_type_class(layout, f));
398
405
  }
399
406
 
400
407
  int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
@@ -434,6 +441,7 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
434
441
  Map_merge_into_self(map, val);
435
442
  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
436
443
  VALUE ary;
444
+ int i;
437
445
 
438
446
  if (TYPE(val) != T_ARRAY) {
439
447
  rb_raise(rb_eArgError,
@@ -441,17 +449,17 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
441
449
  name, rb_class2name(CLASS_OF(val)));
442
450
  }
443
451
  ary = layout_get(self->descriptor->layout, Message_data(self), f);
444
- for (int i = 0; i < RARRAY_LEN(val); i++) {
452
+ for (i = 0; i < RARRAY_LEN(val); i++) {
445
453
  VALUE entry = rb_ary_entry(val, i);
446
454
  if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
447
- entry = create_submsg_from_hash(f, entry);
455
+ entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
448
456
  }
449
457
 
450
458
  RepeatedField_push(ary, entry);
451
459
  }
452
460
  } else {
453
461
  if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
454
- val = create_submsg_from_hash(f, val);
462
+ val = create_submsg_from_hash(self->descriptor->layout, f, val);
455
463
  }
456
464
 
457
465
  layout_set(self->descriptor->layout, Message_data(self), f, val);
@@ -472,7 +480,11 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
472
480
  * Message class are provided on each concrete message class.
473
481
  */
474
482
  VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
483
+ MessageHeader* self;
475
484
  VALUE hash_args;
485
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
486
+
487
+ layout_init(self->descriptor->layout, Message_data(self));
476
488
 
477
489
  if (argc == 0) {
478
490
  return Qnil;
@@ -598,38 +610,44 @@ VALUE Message_inspect(VALUE _self) {
598
610
  */
599
611
  VALUE Message_to_h(VALUE _self) {
600
612
  MessageHeader* self;
601
- VALUE hash;
613
+ VALUE hash = rb_hash_new();
602
614
  upb_msg_field_iter it;
615
+ bool is_proto2;
603
616
  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
604
617
 
605
- hash = rb_hash_new();
618
+ // We currently have a few behaviors that are specific to proto2.
619
+ // This is unfortunate, we should key behaviors off field attributes (like
620
+ // whether a field has presence), not proto2 vs. proto3. We should see if we
621
+ // can change this without breaking users.
622
+ is_proto2 =
623
+ upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2;
606
624
 
607
625
  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
608
626
  !upb_msg_field_done(&it);
609
627
  upb_msg_field_next(&it)) {
610
628
  const upb_fielddef* field = upb_msg_iter_field(&it);
629
+ VALUE msg_value;
630
+ VALUE msg_key;
611
631
 
612
- // For proto2, do not include fields which are not set.
613
- if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
614
- field_contains_hasbit(self->descriptor->layout, field) &&
615
- !layout_has(self->descriptor->layout, Message_data(self), field)) {
632
+ // Do not include fields that are not present (oneof or optional fields).
633
+ if (is_proto2 && upb_fielddef_haspresence(field) &&
634
+ !layout_has(self->descriptor->layout, Message_data(self), field)) {
616
635
  continue;
617
636
  }
618
637
 
619
- VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
620
- field);
621
- VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
638
+ msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
639
+ msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
622
640
  if (is_map_field(field)) {
623
641
  msg_value = Map_to_h(msg_value);
624
642
  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
625
643
  msg_value = RepeatedField_to_ary(msg_value);
626
- if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 &&
627
- RARRAY_LEN(msg_value) == 0) {
644
+ if (is_proto2 && RARRAY_LEN(msg_value) == 0) {
628
645
  continue;
629
646
  }
630
647
 
631
648
  if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
632
- for (int i = 0; i < RARRAY_LEN(msg_value); i++) {
649
+ int i;
650
+ for (i = 0; i < RARRAY_LEN(msg_value); i++) {
633
651
  VALUE elem = rb_ary_entry(msg_value, i);
634
652
  rb_ary_store(msg_value, i, Message_to_h(elem));
635
653
  }
@@ -696,17 +714,11 @@ VALUE Message_descriptor(VALUE klass) {
696
714
  return rb_ivar_get(klass, descriptor_instancevar_interned);
697
715
  }
698
716
 
699
- VALUE build_class_from_descriptor(Descriptor* desc) {
717
+ VALUE build_class_from_descriptor(VALUE descriptor) {
718
+ Descriptor* desc = ruby_to_Descriptor(descriptor);
700
719
  const char *name;
701
720
  VALUE klass;
702
721
 
703
- if (desc->layout == NULL) {
704
- desc->layout = create_layout(desc->msgdef);
705
- }
706
- if (desc->fill_method == NULL) {
707
- desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
708
- }
709
-
710
722
  name = upb_msgdef_fullname(desc->msgdef);
711
723
  if (name == NULL) {
712
724
  rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
@@ -717,8 +729,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
717
729
  // their own toplevel constant class name.
718
730
  rb_intern("Message"),
719
731
  rb_cObject);
720
- rb_ivar_set(klass, descriptor_instancevar_interned,
721
- get_def_obj(desc->msgdef));
732
+ rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
722
733
  rb_define_alloc_func(klass, Message_alloc);
723
734
  rb_require("google/protobuf/message_exts");
724
735
  rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
@@ -737,7 +748,6 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
737
748
  rb_define_method(klass, "eql?", Message_eq, 1);
738
749
  rb_define_method(klass, "hash", Message_hash, 0);
739
750
  rb_define_method(klass, "to_h", Message_to_h, 0);
740
- rb_define_method(klass, "to_hash", Message_to_h, 0);
741
751
  rb_define_method(klass, "inspect", Message_inspect, 0);
742
752
  rb_define_method(klass, "to_s", Message_inspect, 0);
743
753
  rb_define_method(klass, "[]", Message_index, 1);
@@ -803,7 +813,8 @@ VALUE enum_descriptor(VALUE self) {
803
813
  return rb_ivar_get(self, descriptor_instancevar_interned);
804
814
  }
805
815
 
806
- VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
816
+ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
817
+ EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
807
818
  VALUE mod = rb_define_module_id(
808
819
  rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
809
820
 
@@ -824,8 +835,7 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
824
835
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
825
836
  rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
826
837
  rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
827
- rb_ivar_set(mod, descriptor_instancevar_interned,
828
- get_def_obj(enumdesc->enumdef));
838
+ rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
829
839
 
830
840
  return mod;
831
841
  }