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