google-protobuf 3.8.0 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.

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
  }