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.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/defs.c +942 -833
- data/ext/google/protobuf_c/encode_decode.c +482 -301
- data/ext/google/protobuf_c/extconf.rb +2 -4
- data/ext/google/protobuf_c/map.c +39 -58
- data/ext/google/protobuf_c/message.c +124 -114
- data/ext/google/protobuf_c/protobuf.c +30 -15
- data/ext/google/protobuf_c/protobuf.h +109 -57
- data/ext/google/protobuf_c/repeated_field.c +47 -21
- data/ext/google/protobuf_c/storage.c +305 -169
- data/ext/google/protobuf_c/upb.c +5335 -8998
- data/ext/google/protobuf_c/upb.h +4634 -8498
- data/lib/google/protobuf.rb +70 -0
- data/lib/google/protobuf/any_pb.rb +1 -1
- data/lib/google/protobuf/api_pb.rb +3 -3
- data/lib/google/protobuf/duration_pb.rb +1 -1
- data/lib/google/protobuf/empty_pb.rb +1 -1
- data/lib/google/protobuf/field_mask_pb.rb +1 -1
- data/lib/google/protobuf/source_context_pb.rb +1 -1
- data/lib/google/protobuf/struct_pb.rb +4 -4
- data/lib/google/protobuf/timestamp_pb.rb +1 -1
- data/lib/google/protobuf/type_pb.rb +8 -8
- data/lib/google/protobuf/well_known_types.rb +8 -2
- data/lib/google/protobuf/wrappers_pb.rb +9 -9
- data/tests/basic.rb +229 -67
- data/tests/generated_code_test.rb +0 -0
- data/tests/stress.rb +0 -0
- metadata +17 -10
@@ -3,11 +3,9 @@
|
|
3
3
|
require 'mkmf'
|
4
4
|
|
5
5
|
if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
|
6
|
-
|
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=
|
8
|
+
$CFLAGS += " -std=gnu90 -O3 -DNDEBUG"
|
11
9
|
end
|
12
10
|
|
13
11
|
|
data/ext/google/protobuf_c/map.c
CHANGED
@@ -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,
|
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(
|
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,
|
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
|
-
|
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,
|
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,
|
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
|
64
|
-
uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
63
|
+
MessageHeader* msg;
|
65
64
|
VALUE ret;
|
66
65
|
|
67
|
-
|
66
|
+
if (desc->layout == NULL) {
|
67
|
+
create_layout(desc);
|
68
|
+
}
|
68
69
|
|
69
|
-
|
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
|
-
|
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
|
-
|
90
|
-
|
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
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
144
|
-
if (
|
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
|
-
|
148
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
186
|
-
|
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
|
-
|
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 -
|
196
|
+
wrapper_field_name[name_len - 9] = '\0';
|
196
197
|
|
197
198
|
// Check if field exists and is a wrapper type
|
198
|
-
|
199
|
-
|
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 -
|
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
|
-
|
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
|
-
|
249
|
-
|
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
|
-
|
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
|
-
|
337
|
-
|
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(
|
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 (
|
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
|
-
|
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
|
390
|
-
|
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,
|
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 (
|
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
|
-
|
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
|
-
//
|
613
|
-
if (
|
614
|
-
|
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
|
-
|
620
|
-
|
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 (
|
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
|
-
|
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(
|
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(
|
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
|
}
|