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.
- 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
|
}
|