google-protobuf 3.7.0 → 3.8.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 +7 -7
- data/ext/google/protobuf_c/encode_decode.c +41 -1
- data/ext/google/protobuf_c/map.c +8 -2
- data/ext/google/protobuf_c/message.c +124 -8
- data/ext/google/protobuf_c/protobuf.h +5 -3
- data/ext/google/protobuf_c/repeated_field.c +9 -3
- data/ext/google/protobuf_c/storage.c +66 -23
- data/ext/google/protobuf_c/upb.c +478 -316
- data/ext/google/protobuf_c/upb.h +1390 -504
- data/tests/basic.rb +22 -2
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acc61dfa5ec7487b0b62edbf098aca5a5d0ce33145cbab091a892f1ed9f240cf
|
4
|
+
data.tar.gz: f7666d31441737c415008dfa0077657b8afb3c23fd0966f972b305163ffd2a02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 481d523e6d2dc363c73695025811bcc181358513a9a7931d4f19d6c9aab40a085a2e02e97d5370069f339897b8170fd3ddca906952717233e582cd10a9dcfd4c
|
7
|
+
data.tar.gz: 9cf2022047f865793c3edc480147e1e2c27f1d1d676239090c32f3356a8c4f6f6405bde3b8a879aeb9200725d7e340f9fec8d1457ed37411feb3b4d0546dd96c
|
@@ -886,7 +886,7 @@ VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value) {
|
|
886
886
|
upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
|
887
887
|
|
888
888
|
switch (upb_fielddef_type(mut_def)) {
|
889
|
-
case UPB_TYPE_FLOAT:
|
889
|
+
case UPB_TYPE_FLOAT:
|
890
890
|
upb_fielddef_setdefaultfloat(mut_def, NUM2DBL(default_value));
|
891
891
|
break;
|
892
892
|
case UPB_TYPE_DOUBLE:
|
@@ -902,16 +902,16 @@ VALUE FieldDescriptor_default_set(VALUE _self, VALUE default_value) {
|
|
902
902
|
upb_fielddef_setdefaultbool(mut_def, RTEST(default_value));
|
903
903
|
break;
|
904
904
|
case UPB_TYPE_ENUM:
|
905
|
-
case UPB_TYPE_INT32:
|
905
|
+
case UPB_TYPE_INT32:
|
906
906
|
upb_fielddef_setdefaultint32(mut_def, NUM2INT(default_value));
|
907
907
|
break;
|
908
|
-
case UPB_TYPE_INT64:
|
908
|
+
case UPB_TYPE_INT64:
|
909
909
|
upb_fielddef_setdefaultint64(mut_def, NUM2INT(default_value));
|
910
910
|
break;
|
911
|
-
case UPB_TYPE_UINT32:
|
911
|
+
case UPB_TYPE_UINT32:
|
912
912
|
upb_fielddef_setdefaultuint32(mut_def, NUM2UINT(default_value));
|
913
913
|
break;
|
914
|
-
case UPB_TYPE_UINT64:
|
914
|
+
case UPB_TYPE_UINT64:
|
915
915
|
upb_fielddef_setdefaultuint64(mut_def, NUM2UINT(default_value));
|
916
916
|
break;
|
917
917
|
case UPB_TYPE_STRING:
|
@@ -2085,7 +2085,7 @@ VALUE Builder_alloc(VALUE klass) {
|
|
2085
2085
|
|
2086
2086
|
void Builder_register(VALUE module) {
|
2087
2087
|
VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
|
2088
|
-
rb_define_alloc_func(klass, Builder_alloc);
|
2088
|
+
rb_define_alloc_func(klass, Builder_alloc);
|
2089
2089
|
rb_define_method(klass, "initialize", Builder_initialize, 0);
|
2090
2090
|
rb_define_method(klass, "add_file", Builder_add_file, -1);
|
2091
2091
|
rb_define_method(klass, "add_message", Builder_add_message, 1);
|
@@ -2230,7 +2230,7 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
|
|
2230
2230
|
VALUE def_rb = rb_ary_entry(self->pending_list, i);
|
2231
2231
|
if (CLASS_OF(def_rb) == cDescriptor) {
|
2232
2232
|
self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
|
2233
|
-
|
2233
|
+
|
2234
2234
|
if (upb_filedef_syntax(upb_def_file(self->defs[i])) == UPB_SYNTAX_PROTO3) {
|
2235
2235
|
proto3_validate_msgdef((const upb_msgdef*)self->defs[i]);
|
2236
2236
|
}
|
@@ -1061,6 +1061,11 @@ static void put_ruby_value(VALUE value,
|
|
1061
1061
|
upb_sink *sink,
|
1062
1062
|
bool emit_defaults,
|
1063
1063
|
bool is_json) {
|
1064
|
+
if (depth > ENCODE_MAX_NESTING) {
|
1065
|
+
rb_raise(rb_eRuntimeError,
|
1066
|
+
"Maximum recursion depth exceeded during encoding.");
|
1067
|
+
}
|
1068
|
+
|
1064
1069
|
upb_selector_t sel = 0;
|
1065
1070
|
if (upb_fielddef_isprimitive(f)) {
|
1066
1071
|
sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
|
@@ -1232,6 +1237,34 @@ static void putjsonany(VALUE msg_rb, const Descriptor* desc,
|
|
1232
1237
|
upb_sink_endmsg(sink, &status);
|
1233
1238
|
}
|
1234
1239
|
|
1240
|
+
static void putjsonlistvalue(
|
1241
|
+
VALUE msg_rb, const Descriptor* desc,
|
1242
|
+
upb_sink* sink, int depth, bool emit_defaults) {
|
1243
|
+
upb_status status;
|
1244
|
+
upb_sink subsink;
|
1245
|
+
MessageHeader* msg = NULL;
|
1246
|
+
const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
|
1247
|
+
uint32_t offset =
|
1248
|
+
desc->layout->fields[upb_fielddef_index(f)].offset +
|
1249
|
+
sizeof(MessageHeader);
|
1250
|
+
VALUE ary;
|
1251
|
+
|
1252
|
+
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
|
1253
|
+
|
1254
|
+
upb_sink_startmsg(sink);
|
1255
|
+
|
1256
|
+
ary = DEREF(msg, offset, VALUE);
|
1257
|
+
|
1258
|
+
if (ary == Qnil || RepeatedField_size(ary) == 0) {
|
1259
|
+
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
1260
|
+
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
1261
|
+
} else {
|
1262
|
+
putary(ary, f, sink, depth, emit_defaults, true);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
upb_sink_endmsg(sink, &status);
|
1266
|
+
}
|
1267
|
+
|
1235
1268
|
static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
1236
1269
|
upb_sink *sink, int depth, bool emit_defaults,
|
1237
1270
|
bool is_json, bool open_msg) {
|
@@ -1239,11 +1272,18 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|
1239
1272
|
upb_msg_field_iter i;
|
1240
1273
|
upb_status status;
|
1241
1274
|
|
1242
|
-
if (is_json &&
|
1275
|
+
if (is_json &&
|
1276
|
+
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
|
1243
1277
|
putjsonany(msg_rb, desc, sink, depth, emit_defaults);
|
1244
1278
|
return;
|
1245
1279
|
}
|
1246
1280
|
|
1281
|
+
if (is_json &&
|
1282
|
+
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) {
|
1283
|
+
putjsonlistvalue(msg_rb, desc, sink, depth, emit_defaults);
|
1284
|
+
return;
|
1285
|
+
}
|
1286
|
+
|
1247
1287
|
if (open_msg) {
|
1248
1288
|
upb_sink_startmsg(sink);
|
1249
1289
|
}
|
data/ext/google/protobuf_c/map.c
CHANGED
@@ -82,7 +82,7 @@ static VALUE table_key(Map* self, VALUE key,
|
|
82
82
|
case UPB_TYPE_INT64:
|
83
83
|
case UPB_TYPE_UINT32:
|
84
84
|
case UPB_TYPE_UINT64:
|
85
|
-
native_slot_set(self->key_type, Qnil, buf, key);
|
85
|
+
native_slot_set("", self->key_type, Qnil, buf, key);
|
86
86
|
*out_key = buf;
|
87
87
|
*out_length = native_slot_size(self->key_type);
|
88
88
|
break;
|
@@ -386,6 +386,8 @@ VALUE Map_index(VALUE _self, VALUE key) {
|
|
386
386
|
* was just inserted.
|
387
387
|
*/
|
388
388
|
VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
|
389
|
+
rb_check_frozen(_self);
|
390
|
+
|
389
391
|
Map* self = ruby_to_Map(_self);
|
390
392
|
|
391
393
|
char keybuf[TABLE_KEY_BUF_LENGTH];
|
@@ -396,7 +398,7 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
|
|
396
398
|
key = table_key(self, key, keybuf, &keyval, &length);
|
397
399
|
|
398
400
|
mem = value_memory(&v);
|
399
|
-
native_slot_set(self->value_type, self->value_type_class, mem, value);
|
401
|
+
native_slot_set("", self->value_type, self->value_type_class, mem, value);
|
400
402
|
|
401
403
|
// Replace any existing value by issuing a 'remove' operation first.
|
402
404
|
upb_strtable_remove2(&self->table, keyval, length, NULL);
|
@@ -438,6 +440,8 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
|
|
438
440
|
* nil if none was present. Throws an exception if the key is of the wrong type.
|
439
441
|
*/
|
440
442
|
VALUE Map_delete(VALUE _self, VALUE key) {
|
443
|
+
rb_check_frozen(_self);
|
444
|
+
|
441
445
|
Map* self = ruby_to_Map(_self);
|
442
446
|
|
443
447
|
char keybuf[TABLE_KEY_BUF_LENGTH];
|
@@ -461,6 +465,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
|
|
461
465
|
* Removes all entries from the map.
|
462
466
|
*/
|
463
467
|
VALUE Map_clear(VALUE _self) {
|
468
|
+
rb_check_frozen(_self);
|
469
|
+
|
464
470
|
Map* self = ruby_to_Map(_self);
|
465
471
|
|
466
472
|
// Uninit and reinit the table -- this is faster than iterating and doing a
|
@@ -118,9 +118,38 @@ enum {
|
|
118
118
|
METHOD_GETTER = 1,
|
119
119
|
METHOD_SETTER = 2,
|
120
120
|
METHOD_CLEAR = 3,
|
121
|
-
METHOD_PRESENCE = 4
|
121
|
+
METHOD_PRESENCE = 4,
|
122
|
+
METHOD_ENUM_GETTER = 5,
|
123
|
+
METHOD_WRAPPER_GETTER = 6,
|
124
|
+
METHOD_WRAPPER_SETTER = 7
|
122
125
|
};
|
123
126
|
|
127
|
+
// Check if the field is a well known wrapper type
|
128
|
+
static bool is_wrapper_type_field(const upb_fielddef* field) {
|
129
|
+
char* field_type_name = rb_class2name(field_type_class(field));
|
130
|
+
|
131
|
+
return strcmp(field_type_name, "Google::Protobuf::DoubleValue") == 0 ||
|
132
|
+
strcmp(field_type_name, "Google::Protobuf::FloatValue") == 0 ||
|
133
|
+
strcmp(field_type_name, "Google::Protobuf::Int32Value") == 0 ||
|
134
|
+
strcmp(field_type_name, "Google::Protobuf::Int64Value") == 0 ||
|
135
|
+
strcmp(field_type_name, "Google::Protobuf::UInt32Value") == 0 ||
|
136
|
+
strcmp(field_type_name, "Google::Protobuf::UInt64Value") == 0 ||
|
137
|
+
strcmp(field_type_name, "Google::Protobuf::BoolValue") == 0 ||
|
138
|
+
strcmp(field_type_name, "Google::Protobuf::StringValue") == 0 ||
|
139
|
+
strcmp(field_type_name, "Google::Protobuf::BytesValue") == 0;
|
140
|
+
}
|
141
|
+
|
142
|
+
// Get a new Ruby wrapper type and set the initial value
|
143
|
+
static VALUE ruby_wrapper_type(const upb_fielddef* field, const VALUE* value) {
|
144
|
+
if (is_wrapper_type_field(field) && value != Qnil) {
|
145
|
+
VALUE hash = rb_hash_new();
|
146
|
+
rb_hash_aset(hash, rb_str_new2("value"), value);
|
147
|
+
VALUE args[1] = { hash };
|
148
|
+
return rb_class_new_instance(1, args, field_type_class(field));
|
149
|
+
}
|
150
|
+
return Qnil;
|
151
|
+
}
|
152
|
+
|
124
153
|
static int extract_method_call(VALUE method_name, MessageHeader* self,
|
125
154
|
const upb_fielddef **f, const upb_oneofdef **o) {
|
126
155
|
Check_Type(method_name, T_SYMBOL);
|
@@ -153,9 +182,62 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
|
|
153
182
|
accessor_type = METHOD_GETTER;
|
154
183
|
}
|
155
184
|
|
185
|
+
bool has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
|
186
|
+
&test_f, &test_o);
|
187
|
+
|
188
|
+
// Look for wrapper type accessor of the form <field_name>_as_value
|
189
|
+
if (!has_field &&
|
190
|
+
(accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
|
191
|
+
name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
|
192
|
+
// Find the field name
|
193
|
+
char wrapper_field_name[name_len - 8];
|
194
|
+
strncpy(wrapper_field_name, name, name_len - 9);
|
195
|
+
wrapper_field_name[name_len - 7] = '\0';
|
196
|
+
|
197
|
+
// Check if field exists and is a wrapper type
|
198
|
+
const upb_oneofdef* test_o_wrapper;
|
199
|
+
const upb_fielddef* test_f_wrapper;
|
200
|
+
if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name, name_len - 9,
|
201
|
+
&test_f_wrapper, &test_o_wrapper) &&
|
202
|
+
upb_fielddef_type(test_f_wrapper) == UPB_TYPE_MESSAGE &&
|
203
|
+
is_wrapper_type_field(test_f_wrapper)) {
|
204
|
+
// It does exist!
|
205
|
+
has_field = true;
|
206
|
+
if (accessor_type == METHOD_SETTER) {
|
207
|
+
accessor_type = METHOD_WRAPPER_SETTER;
|
208
|
+
} else {
|
209
|
+
accessor_type = METHOD_WRAPPER_GETTER;
|
210
|
+
}
|
211
|
+
test_o = test_o_wrapper;
|
212
|
+
test_f = test_f_wrapper;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
// Look for enum accessor of the form <enum_name>_const
|
217
|
+
if (!has_field && accessor_type == METHOD_GETTER &&
|
218
|
+
name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
|
219
|
+
|
220
|
+
// Find enum field name
|
221
|
+
char enum_name[name_len - 5];
|
222
|
+
strncpy(enum_name, name, name_len - 6);
|
223
|
+
enum_name[name_len - 4] = '\0';
|
224
|
+
|
225
|
+
// Check if enum field exists
|
226
|
+
const upb_oneofdef* test_o_enum;
|
227
|
+
const upb_fielddef* test_f_enum;
|
228
|
+
if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
|
229
|
+
&test_f_enum, &test_o_enum) &&
|
230
|
+
upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
|
231
|
+
// It does exist!
|
232
|
+
has_field = true;
|
233
|
+
accessor_type = METHOD_ENUM_GETTER;
|
234
|
+
test_o = test_o_enum;
|
235
|
+
test_f = test_f_enum;
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
156
239
|
// Verify the name corresponds to a oneof or field in this message.
|
157
|
-
if (!
|
158
|
-
&test_f, &test_o)) {
|
240
|
+
if (!has_field) {
|
159
241
|
return METHOD_UNKNOWN;
|
160
242
|
}
|
161
243
|
|
@@ -212,10 +294,11 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
212
294
|
int accessor_type = extract_method_call(argv[0], self, &f, &o);
|
213
295
|
if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
|
214
296
|
return rb_call_super(argc, argv);
|
215
|
-
} else if (accessor_type == METHOD_SETTER) {
|
297
|
+
} else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
|
216
298
|
if (argc != 2) {
|
217
299
|
rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
|
218
300
|
}
|
301
|
+
rb_check_frozen(_self);
|
219
302
|
} else if (argc != 1) {
|
220
303
|
rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
|
221
304
|
}
|
@@ -231,13 +314,13 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
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,35 @@ 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
|
+
if (value != Qnil) {
|
337
|
+
value = rb_funcall(value, rb_intern("value"), 0);
|
338
|
+
}
|
339
|
+
return value;
|
340
|
+
} else if (accessor_type == METHOD_WRAPPER_SETTER) {
|
341
|
+
VALUE wrapper = ruby_wrapper_type(f, argv[1]);
|
342
|
+
layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
|
343
|
+
return Qnil;
|
344
|
+
} else if (accessor_type == METHOD_ENUM_GETTER) {
|
345
|
+
VALUE enum_type = field_type_class(f);
|
346
|
+
VALUE method = rb_intern("const_get");
|
347
|
+
VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
|
348
|
+
|
349
|
+
// Map repeated fields to a new type with ints
|
350
|
+
if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
|
351
|
+
int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
|
352
|
+
VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
|
353
|
+
VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
|
354
|
+
for (int i = 0; i < array_size; i++) {
|
355
|
+
VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
|
356
|
+
rb_intern("at"), 1, INT2NUM(i)));
|
357
|
+
rb_funcall(array, rb_intern("push"), 1, entry);
|
358
|
+
}
|
359
|
+
return array;
|
360
|
+
}
|
361
|
+
// Convert the value for singular fields
|
362
|
+
return rb_funcall(enum_type, method, 1, raw_value);
|
251
363
|
} else {
|
252
364
|
return layout_get(self->descriptor->layout, Message_data(self), f);
|
253
365
|
}
|
@@ -315,7 +427,8 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
315
427
|
|
316
428
|
if (TYPE(val) != T_HASH) {
|
317
429
|
rb_raise(rb_eArgError,
|
318
|
-
"Expected Hash object as initializer value for map field '%s'.",
|
430
|
+
"Expected Hash object as initializer value for map field '%s' (given %s).",
|
431
|
+
name, rb_class2name(CLASS_OF(val)));
|
319
432
|
}
|
320
433
|
map = layout_get(self->descriptor->layout, Message_data(self), f);
|
321
434
|
Map_merge_into_self(map, val);
|
@@ -324,7 +437,8 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
324
437
|
|
325
438
|
if (TYPE(val) != T_ARRAY) {
|
326
439
|
rb_raise(rb_eArgError,
|
327
|
-
"Expected array as initializer value for repeated field '%s'.",
|
440
|
+
"Expected array as initializer value for repeated field '%s' (given %s).",
|
441
|
+
name, rb_class2name(CLASS_OF(val)));
|
328
442
|
}
|
329
443
|
ary = layout_get(self->descriptor->layout, Message_data(self), f);
|
330
444
|
for (int i = 0; i < RARRAY_LEN(val); i++) {
|
@@ -620,10 +734,12 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
620
734
|
// Also define #clone so that we don't inherit Object#clone.
|
621
735
|
rb_define_method(klass, "clone", Message_dup, 0);
|
622
736
|
rb_define_method(klass, "==", Message_eq, 1);
|
737
|
+
rb_define_method(klass, "eql?", Message_eq, 1);
|
623
738
|
rb_define_method(klass, "hash", Message_hash, 0);
|
624
739
|
rb_define_method(klass, "to_h", Message_to_h, 0);
|
625
740
|
rb_define_method(klass, "to_hash", Message_to_h, 0);
|
626
741
|
rb_define_method(klass, "inspect", Message_inspect, 0);
|
742
|
+
rb_define_method(klass, "to_s", Message_inspect, 0);
|
627
743
|
rb_define_method(klass, "[]", Message_index, 1);
|
628
744
|
rb_define_method(klass, "[]=", Message_index_set, 2);
|
629
745
|
rb_define_singleton_method(klass, "decode", Message_decode, 1);
|
@@ -337,14 +337,16 @@ VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
|
|
337
337
|
#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
|
338
338
|
|
339
339
|
size_t native_slot_size(upb_fieldtype_t type);
|
340
|
-
void native_slot_set(
|
340
|
+
void native_slot_set(const char* name,
|
341
|
+
upb_fieldtype_t type,
|
341
342
|
VALUE type_class,
|
342
343
|
void* memory,
|
343
344
|
VALUE value);
|
344
345
|
// Atomically (with respect to Ruby VM calls) either update the value and set a
|
345
346
|
// oneof case, or do neither. If |case_memory| is null, then no case value is
|
346
347
|
// set.
|
347
|
-
void native_slot_set_value_and_case(
|
348
|
+
void native_slot_set_value_and_case(const char* name,
|
349
|
+
upb_fieldtype_t type,
|
348
350
|
VALUE type_class,
|
349
351
|
void* memory,
|
350
352
|
VALUE value,
|
@@ -360,7 +362,7 @@ void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from);
|
|
360
362
|
bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
|
361
363
|
|
362
364
|
VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value);
|
363
|
-
void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value);
|
365
|
+
void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE value);
|
364
366
|
|
365
367
|
extern rb_encoding* kRubyStringUtf8Encoding;
|
366
368
|
extern rb_encoding* kRubyStringASCIIEncoding;
|
@@ -178,7 +178,7 @@ VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
|
|
178
178
|
}
|
179
179
|
|
180
180
|
memory = RepeatedField_memoryat(self, index, element_size);
|
181
|
-
native_slot_set(field_type, field_type_class, memory, val);
|
181
|
+
native_slot_set("", field_type, field_type_class, memory, val);
|
182
182
|
return Qnil;
|
183
183
|
}
|
184
184
|
|
@@ -217,12 +217,18 @@ VALUE RepeatedField_push(VALUE _self, VALUE val) {
|
|
217
217
|
|
218
218
|
RepeatedField_reserve(self, self->size + 1);
|
219
219
|
memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
|
220
|
-
native_slot_set(field_type, self->field_type_class, memory, val);
|
220
|
+
native_slot_set("", field_type, self->field_type_class, memory, val);
|
221
221
|
// native_slot_set may raise an error; bump size only after set.
|
222
222
|
self->size++;
|
223
223
|
return _self;
|
224
224
|
}
|
225
225
|
|
226
|
+
VALUE RepeatedField_push_vararg(VALUE _self, VALUE args) {
|
227
|
+
for (int i = 0; i < RARRAY_LEN(args); i++) {
|
228
|
+
RepeatedField_push(_self, rb_ary_entry(args, i));
|
229
|
+
}
|
230
|
+
return _self;
|
231
|
+
}
|
226
232
|
|
227
233
|
// Used by parsing handlers.
|
228
234
|
void RepeatedField_push_native(VALUE _self, void* data) {
|
@@ -635,7 +641,7 @@ void RepeatedField_register(VALUE module) {
|
|
635
641
|
rb_define_method(klass, "[]", RepeatedField_index, -1);
|
636
642
|
rb_define_method(klass, "at", RepeatedField_index, -1);
|
637
643
|
rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
|
638
|
-
rb_define_method(klass, "push",
|
644
|
+
rb_define_method(klass, "push", RepeatedField_push_vararg, -2);
|
639
645
|
rb_define_method(klass, "<<", RepeatedField_push, 1);
|
640
646
|
rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
|
641
647
|
rb_define_method(klass, "replace", RepeatedField_replace, 1);
|
@@ -65,9 +65,10 @@ static bool is_ruby_num(VALUE value) {
|
|
65
65
|
TYPE(value) == T_BIGNUM);
|
66
66
|
}
|
67
67
|
|
68
|
-
void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
|
68
|
+
void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE val) {
|
69
69
|
if (!is_ruby_num(val)) {
|
70
|
-
rb_raise(cTypeError, "Expected number type for integral field."
|
70
|
+
rb_raise(cTypeError, "Expected number type for integral field '%s' (given %s).",
|
71
|
+
name, rb_class2name(CLASS_OF(val)));
|
71
72
|
}
|
72
73
|
|
73
74
|
// NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
|
@@ -77,13 +78,15 @@ void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
|
|
77
78
|
double dbl_val = NUM2DBL(val);
|
78
79
|
if (floor(dbl_val) != dbl_val) {
|
79
80
|
rb_raise(rb_eRangeError,
|
80
|
-
"Non-integral floating point value assigned to integer field."
|
81
|
+
"Non-integral floating point value assigned to integer field '%s' (given %s).",
|
82
|
+
name, rb_class2name(CLASS_OF(val)));
|
81
83
|
}
|
82
84
|
}
|
83
85
|
if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
|
84
86
|
if (NUM2DBL(val) < 0) {
|
85
87
|
rb_raise(rb_eRangeError,
|
86
|
-
"Assigning negative value to unsigned integer field."
|
88
|
+
"Assigning negative value to unsigned integer field '%s' (given %s).",
|
89
|
+
name, rb_class2name(CLASS_OF(val)));
|
87
90
|
}
|
88
91
|
}
|
89
92
|
}
|
@@ -108,12 +111,14 @@ VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) {
|
|
108
111
|
return value;
|
109
112
|
}
|
110
113
|
|
111
|
-
void native_slot_set(
|
114
|
+
void native_slot_set(const char* name,
|
115
|
+
upb_fieldtype_t type, VALUE type_class,
|
112
116
|
void* memory, VALUE value) {
|
113
|
-
native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
|
117
|
+
native_slot_set_value_and_case(name, type, type_class, memory, value, NULL, 0);
|
114
118
|
}
|
115
119
|
|
116
|
-
void native_slot_set_value_and_case(
|
120
|
+
void native_slot_set_value_and_case(const char* name,
|
121
|
+
upb_fieldtype_t type, VALUE type_class,
|
117
122
|
void* memory, VALUE value,
|
118
123
|
uint32_t* case_memory,
|
119
124
|
uint32_t case_number) {
|
@@ -124,13 +129,15 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
124
129
|
switch (type) {
|
125
130
|
case UPB_TYPE_FLOAT:
|
126
131
|
if (!is_ruby_num(value)) {
|
127
|
-
rb_raise(cTypeError, "Expected number type for float field."
|
132
|
+
rb_raise(cTypeError, "Expected number type for float field '%s' (given %s).",
|
133
|
+
name, rb_class2name(CLASS_OF(value)));
|
128
134
|
}
|
129
135
|
DEREF(memory, float) = NUM2DBL(value);
|
130
136
|
break;
|
131
137
|
case UPB_TYPE_DOUBLE:
|
132
138
|
if (!is_ruby_num(value)) {
|
133
|
-
rb_raise(cTypeError, "Expected number type for double field."
|
139
|
+
rb_raise(cTypeError, "Expected number type for double field '%s' (given %s).",
|
140
|
+
name, rb_class2name(CLASS_OF(value)));
|
134
141
|
}
|
135
142
|
DEREF(memory, double) = NUM2DBL(value);
|
136
143
|
break;
|
@@ -141,7 +148,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
141
148
|
} else if (value == Qfalse) {
|
142
149
|
val = 0;
|
143
150
|
} else {
|
144
|
-
rb_raise(cTypeError, "Invalid argument for boolean field."
|
151
|
+
rb_raise(cTypeError, "Invalid argument for boolean field '%s' (given %s).",
|
152
|
+
name, rb_class2name(CLASS_OF(value)));
|
145
153
|
}
|
146
154
|
DEREF(memory, int8_t) = val;
|
147
155
|
break;
|
@@ -150,7 +158,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
150
158
|
if (CLASS_OF(value) == rb_cSymbol) {
|
151
159
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
152
160
|
} else if (CLASS_OF(value) != rb_cString) {
|
153
|
-
rb_raise(cTypeError, "Invalid argument for string field."
|
161
|
+
rb_raise(cTypeError, "Invalid argument for string field '%s' (given %s).",
|
162
|
+
name, rb_class2name(CLASS_OF(value)));
|
154
163
|
}
|
155
164
|
|
156
165
|
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
|
@@ -158,7 +167,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
158
167
|
|
159
168
|
case UPB_TYPE_BYTES: {
|
160
169
|
if (CLASS_OF(value) != rb_cString) {
|
161
|
-
rb_raise(cTypeError, "Invalid argument for
|
170
|
+
rb_raise(cTypeError, "Invalid argument for bytes field '%s' (given %s).",
|
171
|
+
name, rb_class2name(CLASS_OF(value)));
|
162
172
|
}
|
163
173
|
|
164
174
|
DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
|
@@ -168,9 +178,39 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
168
178
|
if (CLASS_OF(value) == CLASS_OF(Qnil)) {
|
169
179
|
value = Qnil;
|
170
180
|
} else if (CLASS_OF(value) != type_class) {
|
171
|
-
|
172
|
-
|
173
|
-
|
181
|
+
// check for possible implicit conversions
|
182
|
+
VALUE converted_value = NULL;
|
183
|
+
char* field_type_name = rb_class2name(type_class);
|
184
|
+
|
185
|
+
if (strcmp(field_type_name, "Google::Protobuf::Timestamp") == 0 &&
|
186
|
+
rb_obj_is_kind_of(value, rb_cTime)) {
|
187
|
+
// Time -> Google::Protobuf::Timestamp
|
188
|
+
VALUE hash = rb_hash_new();
|
189
|
+
rb_hash_aset(hash, rb_str_new2("seconds"), rb_funcall(value, rb_intern("to_i"), 0));
|
190
|
+
rb_hash_aset(hash, rb_str_new2("nanos"), rb_funcall(value, rb_intern("nsec"), 0));
|
191
|
+
VALUE args[1] = { hash };
|
192
|
+
converted_value = rb_class_new_instance(1, args, type_class);
|
193
|
+
} else if (strcmp(field_type_name, "Google::Protobuf::Duration") == 0 &&
|
194
|
+
rb_obj_is_kind_of(value, rb_cNumeric)) {
|
195
|
+
// Numeric -> Google::Protobuf::Duration
|
196
|
+
VALUE hash = rb_hash_new();
|
197
|
+
rb_hash_aset(hash, rb_str_new2("seconds"), rb_funcall(value, rb_intern("to_i"), 0));
|
198
|
+
VALUE n_value = rb_funcall(value, rb_intern("remainder"), 1, INT2NUM(1));
|
199
|
+
n_value = rb_funcall(n_value, rb_intern("*"), 1, INT2NUM(1000000000));
|
200
|
+
n_value = rb_funcall(n_value, rb_intern("round"), 0);
|
201
|
+
rb_hash_aset(hash, rb_str_new2("nanos"), n_value);
|
202
|
+
VALUE args[1] = { hash };
|
203
|
+
converted_value = rb_class_new_instance(1, args, type_class);
|
204
|
+
}
|
205
|
+
|
206
|
+
// raise if no suitable conversaion could be found
|
207
|
+
if (converted_value == NULL) {
|
208
|
+
rb_raise(cTypeError,
|
209
|
+
"Invalid type %s to assign to submessage field '%s'.",
|
210
|
+
rb_class2name(CLASS_OF(value)), name);
|
211
|
+
} else {
|
212
|
+
value = converted_value;
|
213
|
+
}
|
174
214
|
}
|
175
215
|
DEREF(memory, VALUE) = value;
|
176
216
|
break;
|
@@ -181,18 +221,18 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
181
221
|
value = rb_funcall(value, rb_intern("to_sym"), 0);
|
182
222
|
} else if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
|
183
223
|
rb_raise(cTypeError,
|
184
|
-
"Expected number or symbol type for enum field.");
|
224
|
+
"Expected number or symbol type for enum field '%s'.", name);
|
185
225
|
}
|
186
226
|
if (TYPE(value) == T_SYMBOL) {
|
187
227
|
// Ensure that the given symbol exists in the enum module.
|
188
228
|
VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
|
189
229
|
if (lookup == Qnil) {
|
190
|
-
rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
|
230
|
+
rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name);
|
191
231
|
} else {
|
192
232
|
int_val = NUM2INT(lookup);
|
193
233
|
}
|
194
234
|
} else {
|
195
|
-
native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
|
235
|
+
native_slot_check_int_range_precision(name, UPB_TYPE_INT32, value);
|
196
236
|
int_val = NUM2INT(value);
|
197
237
|
}
|
198
238
|
DEREF(memory, int32_t) = int_val;
|
@@ -202,7 +242,7 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
|
|
202
242
|
case UPB_TYPE_INT64:
|
203
243
|
case UPB_TYPE_UINT32:
|
204
244
|
case UPB_TYPE_UINT64:
|
205
|
-
native_slot_check_int_range_precision(type, value);
|
245
|
+
native_slot_check_int_range_precision(name, type, value);
|
206
246
|
switch (type) {
|
207
247
|
case UPB_TYPE_INT32:
|
208
248
|
DEREF(memory, int32_t) = NUM2INT(value);
|
@@ -658,8 +698,9 @@ void layout_clear(MessageLayout* layout,
|
|
658
698
|
|
659
699
|
DEREF(memory, VALUE) = ary;
|
660
700
|
} else {
|
661
|
-
native_slot_set(
|
662
|
-
|
701
|
+
native_slot_set(upb_fielddef_name(field),
|
702
|
+
upb_fielddef_type(field), field_type_class(field),
|
703
|
+
memory, layout_get_default(field));
|
663
704
|
}
|
664
705
|
}
|
665
706
|
|
@@ -816,6 +857,7 @@ void layout_set(MessageLayout* layout,
|
|
816
857
|
// use native_slot_set_value_and_case(), which ensures that both the value
|
817
858
|
// and case number are altered atomically (w.r.t. the Ruby VM).
|
818
859
|
native_slot_set_value_and_case(
|
860
|
+
upb_fielddef_name(field),
|
819
861
|
upb_fielddef_type(field), field_type_class(field),
|
820
862
|
memory, val,
|
821
863
|
oneof_case, upb_fielddef_number(field));
|
@@ -827,8 +869,9 @@ void layout_set(MessageLayout* layout,
|
|
827
869
|
check_repeated_field_type(val, field);
|
828
870
|
DEREF(memory, VALUE) = val;
|
829
871
|
} else {
|
830
|
-
native_slot_set(
|
831
|
-
|
872
|
+
native_slot_set(upb_fielddef_name(field),
|
873
|
+
upb_fielddef_type(field), field_type_class(field),
|
874
|
+
memory, val);
|
832
875
|
}
|
833
876
|
|
834
877
|
if (layout->fields[upb_fielddef_index(field)].hasbit !=
|