google-protobuf 3.15.6 → 3.17.3
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 +35 -8
- data/ext/google/protobuf_c/extconf.rb +1 -0
- data/ext/google/protobuf_c/map.c +5 -3
- data/ext/google/protobuf_c/map.h +2 -1
- data/ext/google/protobuf_c/message.c +19 -11
- data/ext/google/protobuf_c/protobuf.c +108 -16
- data/ext/google/protobuf_c/protobuf.h +6 -0
- data/ext/google/protobuf_c/repeated_field.c +4 -2
- data/ext/google/protobuf_c/repeated_field.h +2 -1
- data/ext/google/protobuf_c/ruby-upb.c +756 -812
- data/ext/google/protobuf_c/ruby-upb.h +288 -329
- data/tests/basic.rb +7 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1ded185284a923b15342a8f5600e74debdd40f99faf40c35c1b8675636406ff
|
4
|
+
data.tar.gz: '018d94176b65ef8ddcb7b27b785dfaac029ada709e999e58bcc194bff018f984'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0c47bf01f20c9327b089e60d2bb36d1eee98483eb862e7434b9409a5b18dc24ab38808660b997fbbb66ed21fa012417aaeb1164019ea715c7547d5928ca1d37
|
7
|
+
data.tar.gz: 01e37346bed78463df8a19d1b60315494065094b13aa4f76bbffb872be51f163297542d8a6db2a8d7902c2987312e06f23d3b55e2ed6833f988733c90f11e97c
|
@@ -868,6 +868,20 @@ static VALUE FieldDescriptor_default(VALUE _self) {
|
|
868
868
|
return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
|
869
869
|
}
|
870
870
|
|
871
|
+
|
872
|
+
/*
|
873
|
+
* call-seq:
|
874
|
+
* FieldDescriptor.json_name => json_name
|
875
|
+
*
|
876
|
+
* Returns this field's json_name, as a Ruby string, or nil if not yet set.
|
877
|
+
*/
|
878
|
+
static VALUE FieldDescriptor_json_name(VALUE _self) {
|
879
|
+
FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
|
880
|
+
const upb_fielddef *f = self->fielddef;
|
881
|
+
const char *json_name = upb_fielddef_jsonname(f);
|
882
|
+
return rb_str_new2(json_name);
|
883
|
+
}
|
884
|
+
|
871
885
|
/*
|
872
886
|
* call-seq:
|
873
887
|
* FieldDescriptor.label => label
|
@@ -1043,6 +1057,7 @@ static void FieldDescriptor_register(VALUE module) {
|
|
1043
1057
|
rb_define_method(klass, "name", FieldDescriptor_name, 0);
|
1044
1058
|
rb_define_method(klass, "type", FieldDescriptor__type, 0);
|
1045
1059
|
rb_define_method(klass, "default", FieldDescriptor_default, 0);
|
1060
|
+
rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0);
|
1046
1061
|
rb_define_method(klass, "label", FieldDescriptor_label, 0);
|
1047
1062
|
rb_define_method(klass, "number", FieldDescriptor_number, 0);
|
1048
1063
|
rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
|
@@ -1750,6 +1765,16 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
|
|
1750
1765
|
field_proto,
|
1751
1766
|
FileBuilderContext_strdup(self->file_builder, default_value));
|
1752
1767
|
}
|
1768
|
+
|
1769
|
+
if (rb_funcall(options, rb_intern("key?"), 1,
|
1770
|
+
ID2SYM(rb_intern("json_name"))) == Qtrue) {
|
1771
|
+
VALUE json_name =
|
1772
|
+
rb_hash_lookup(options, ID2SYM(rb_intern("json_name")));
|
1773
|
+
|
1774
|
+
google_protobuf_FieldDescriptorProto_set_json_name(
|
1775
|
+
field_proto,
|
1776
|
+
FileBuilderContext_strdup(self->file_builder, json_name));
|
1777
|
+
}
|
1753
1778
|
}
|
1754
1779
|
|
1755
1780
|
if (oneof_index >= 0) {
|
@@ -1899,18 +1924,20 @@ static VALUE MessageBuilderContext_required(int argc, VALUE* argv,
|
|
1899
1924
|
*/
|
1900
1925
|
static VALUE MessageBuilderContext_repeated(int argc, VALUE* argv,
|
1901
1926
|
VALUE _self) {
|
1902
|
-
VALUE name, type, number
|
1927
|
+
VALUE name, type, number;
|
1928
|
+
VALUE type_class, options = Qnil;
|
1903
1929
|
|
1904
|
-
|
1905
|
-
|
1930
|
+
rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
|
1931
|
+
|
1932
|
+
// Allow passing (name, type, number, options) or
|
1933
|
+
// (name, type, number, type_class, options)
|
1934
|
+
if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
|
1935
|
+
options = type_class;
|
1936
|
+
type_class = Qnil;
|
1906
1937
|
}
|
1907
|
-
name = argv[0];
|
1908
|
-
type = argv[1];
|
1909
|
-
number = argv[2];
|
1910
|
-
type_class = (argc > 3) ? argv[3] : Qnil;
|
1911
1938
|
|
1912
1939
|
msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
|
1913
|
-
|
1940
|
+
options, -1, false);
|
1914
1941
|
|
1915
1942
|
return Qnil;
|
1916
1943
|
}
|
data/ext/google/protobuf_c/map.c
CHANGED
@@ -167,7 +167,8 @@ VALUE Map_deep_copy(VALUE obj) {
|
|
167
167
|
new_arena_rb);
|
168
168
|
}
|
169
169
|
|
170
|
-
const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef
|
170
|
+
const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
|
171
|
+
upb_arena* arena) {
|
171
172
|
const upb_fielddef* key_field = map_field_key(field);
|
172
173
|
const upb_fielddef* value_field = map_field_value(field);
|
173
174
|
TypeInfo value_type_info = TypeInfo_get(value_field);
|
@@ -189,6 +190,7 @@ const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef *field) {
|
|
189
190
|
rb_raise(cTypeError, "Map value type has wrong message/enum class");
|
190
191
|
}
|
191
192
|
|
193
|
+
Arena_fuse(self->arena, arena);
|
192
194
|
return self->map;
|
193
195
|
}
|
194
196
|
|
@@ -236,7 +238,7 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
|
|
236
238
|
upb_msg *self_msg = Map_GetMutable(_self);
|
237
239
|
size_t iter = UPB_MAP_BEGIN;
|
238
240
|
|
239
|
-
|
241
|
+
Arena_fuse(other->arena, arena);
|
240
242
|
|
241
243
|
if (self->key_type != other->key_type ||
|
242
244
|
self->value_type_info.type != other->value_type_info.type ||
|
@@ -511,7 +513,7 @@ static VALUE Map_dup(VALUE _self) {
|
|
511
513
|
upb_arena *arena = Arena_get(new_self->arena);
|
512
514
|
upb_map *new_map = Map_GetMutable(new_map_rb);
|
513
515
|
|
514
|
-
|
516
|
+
Arena_fuse(self->arena, arena);
|
515
517
|
|
516
518
|
while (upb_mapiter_next(self->map, &iter)) {
|
517
519
|
upb_msgval key = upb_mapiter_key(self->map, iter);
|
data/ext/google/protobuf_c/map.h
CHANGED
@@ -44,7 +44,8 @@ VALUE Map_GetRubyWrapper(upb_map *map, upb_fieldtype_t key_type,
|
|
44
44
|
// Gets the underlying upb_map for this Ruby map object, which must have
|
45
45
|
// key/value type that match |field|. If this is not a map or the type doesn't
|
46
46
|
// match, raises an exception.
|
47
|
-
const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field
|
47
|
+
const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field,
|
48
|
+
upb_arena *arena);
|
48
49
|
|
49
50
|
// Implements #inspect for this map by appending its contents to |b|.
|
50
51
|
void Map_Inspect(StringBuilder *b, const upb_map *map, upb_fieldtype_t key_type,
|
@@ -277,9 +277,9 @@ static void Message_setfield(upb_msg* msg, const upb_fielddef* f, VALUE val,
|
|
277
277
|
upb_arena* arena) {
|
278
278
|
upb_msgval msgval;
|
279
279
|
if (upb_fielddef_ismap(f)) {
|
280
|
-
msgval.map_val = Map_GetUpbMap(val, f);
|
280
|
+
msgval.map_val = Map_GetUpbMap(val, f, arena);
|
281
281
|
} else if (upb_fielddef_isseq(f)) {
|
282
|
-
msgval.array_val = RepeatedField_GetUpbArray(val, f);
|
282
|
+
msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
|
283
283
|
} else {
|
284
284
|
if (val == Qnil &&
|
285
285
|
(upb_fielddef_issubmsg(f) || upb_fielddef_realcontainingoneof(f))) {
|
@@ -660,7 +660,7 @@ static VALUE Message_dup(VALUE _self) {
|
|
660
660
|
// TODO(copy unknown fields?)
|
661
661
|
// TODO(use official upb msg copy function)
|
662
662
|
memcpy((upb_msg*)new_msg_self->msg, self->msg, size);
|
663
|
-
|
663
|
+
Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
|
664
664
|
return new_msg;
|
665
665
|
}
|
666
666
|
|
@@ -697,16 +697,13 @@ bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
|
|
697
697
|
* field is of a primitive type).
|
698
698
|
*/
|
699
699
|
static VALUE Message_eq(VALUE _self, VALUE _other) {
|
700
|
-
if (
|
701
|
-
return Qfalse;
|
702
|
-
}
|
700
|
+
if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse;
|
703
701
|
|
704
702
|
Message* self = ruby_to_Message(_self);
|
705
703
|
Message* other = ruby_to_Message(_other);
|
704
|
+
assert(self->msgdef == other->msgdef);
|
706
705
|
|
707
|
-
return Message_Equal(self->msg, other->msg, self->msgdef)
|
708
|
-
? Qtrue
|
709
|
-
: Qfalse;
|
706
|
+
return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
|
710
707
|
}
|
711
708
|
|
712
709
|
uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
|
@@ -737,7 +734,10 @@ uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
|
|
737
734
|
*/
|
738
735
|
static VALUE Message_hash(VALUE _self) {
|
739
736
|
Message* self = ruby_to_Message(_self);
|
740
|
-
|
737
|
+
uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0);
|
738
|
+
// RUBY_FIXNUM_MAX should be one less than a power of 2.
|
739
|
+
assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0);
|
740
|
+
return INT2FIX(hash_value & RUBY_FIXNUM_MAX);
|
741
741
|
}
|
742
742
|
|
743
743
|
/*
|
@@ -794,6 +794,14 @@ static VALUE Message_CreateHash(const upb_msg *msg, const upb_msgdef *m) {
|
|
794
794
|
VALUE msg_value;
|
795
795
|
VALUE msg_key;
|
796
796
|
|
797
|
+
if (!is_proto2 && upb_fielddef_issubmsg(field) &&
|
798
|
+
!upb_fielddef_isseq(field) && !upb_msg_has(msg, field)) {
|
799
|
+
// TODO: Legacy behavior, remove when we fix the is_proto2 differences.
|
800
|
+
msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
|
801
|
+
rb_hash_aset(hash, msg_key, Qnil);
|
802
|
+
continue;
|
803
|
+
}
|
804
|
+
|
797
805
|
// Do not include fields that are not present (oneof or optional fields).
|
798
806
|
if (is_proto2 && upb_fielddef_haspresence(field) &&
|
799
807
|
!upb_msg_has(msg, field)) {
|
@@ -1306,7 +1314,7 @@ const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
|
|
1306
1314
|
}
|
1307
1315
|
|
1308
1316
|
Message* self = ruby_to_Message(value);
|
1309
|
-
|
1317
|
+
Arena_fuse(self->arena, arena);
|
1310
1318
|
|
1311
1319
|
return self->msg;
|
1312
1320
|
}
|
@@ -37,7 +37,7 @@
|
|
37
37
|
#include "message.h"
|
38
38
|
#include "repeated_field.h"
|
39
39
|
|
40
|
-
VALUE
|
40
|
+
VALUE cParseError;
|
41
41
|
VALUE cTypeError;
|
42
42
|
|
43
43
|
const upb_fielddef* map_field_key(const upb_fielddef* field) {
|
@@ -180,6 +180,7 @@ static void Arena_mark(void *data) {
|
|
180
180
|
static void Arena_free(void *data) {
|
181
181
|
Arena *arena = data;
|
182
182
|
upb_arena_free(arena->arena);
|
183
|
+
xfree(arena);
|
183
184
|
}
|
184
185
|
|
185
186
|
static VALUE cArena;
|
@@ -203,6 +204,16 @@ upb_arena *Arena_get(VALUE _arena) {
|
|
203
204
|
return arena->arena;
|
204
205
|
}
|
205
206
|
|
207
|
+
void Arena_fuse(VALUE _arena, upb_arena *other) {
|
208
|
+
Arena *arena;
|
209
|
+
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
210
|
+
if (!upb_arena_fuse(arena->arena, other)) {
|
211
|
+
rb_raise(rb_eRuntimeError,
|
212
|
+
"Unable to fuse arenas. This should never happen since Ruby does "
|
213
|
+
"not use initial blocks");
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
206
217
|
VALUE Arena_new() {
|
207
218
|
return Arena_alloc(cArena);
|
208
219
|
}
|
@@ -237,8 +248,16 @@ void Arena_register(VALUE module) {
|
|
237
248
|
// We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
|
238
249
|
// to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
|
239
250
|
// keys.
|
240
|
-
|
241
|
-
|
251
|
+
//
|
252
|
+
// We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
|
253
|
+
// means it may not be possible to fit a pointer into a Fixnum. Keys are
|
254
|
+
// pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
|
255
|
+
// they overflow and require allocating a Bignum, they could get collected
|
256
|
+
// prematurely, thus removing the cache entry. This happens on 64-bit Windows,
|
257
|
+
// on which pointers are 64 bits but longs are 32 bits. In this case, we enable
|
258
|
+
// the secondary Hash to hold the keys and prevent them from being collected.
|
259
|
+
|
260
|
+
#if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
|
242
261
|
#define USE_SECONDARY_MAP 0
|
243
262
|
#else
|
244
263
|
#define USE_SECONDARY_MAP 1
|
@@ -251,15 +270,81 @@ void Arena_register(VALUE module) {
|
|
251
270
|
// The object is used only for its identity; it does not contain any data.
|
252
271
|
VALUE secondary_map = Qnil;
|
253
272
|
|
273
|
+
// Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
|
274
|
+
// iterates over the map which cannot happen in parallel with insertions, or
|
275
|
+
// Ruby will throw:
|
276
|
+
// can't add a new key into hash during iteration (RuntimeError)
|
277
|
+
VALUE secondary_map_mutex = Qnil;
|
278
|
+
|
279
|
+
// Lambda that will GC entries from the secondary map that are no longer present
|
280
|
+
// in the primary map.
|
281
|
+
VALUE gc_secondary_map_lambda = Qnil;
|
282
|
+
ID length;
|
283
|
+
|
284
|
+
extern VALUE weak_obj_cache;
|
285
|
+
|
254
286
|
static void SecondaryMap_Init() {
|
255
287
|
rb_gc_register_address(&secondary_map);
|
288
|
+
rb_gc_register_address(&gc_secondary_map_lambda);
|
289
|
+
rb_gc_register_address(&secondary_map_mutex);
|
256
290
|
secondary_map = rb_hash_new();
|
291
|
+
gc_secondary_map_lambda = rb_eval_string(
|
292
|
+
"->(secondary, weak) {\n"
|
293
|
+
" secondary.delete_if { |k, v| !weak.key?(v) }\n"
|
294
|
+
"}\n");
|
295
|
+
secondary_map_mutex = rb_mutex_new();
|
296
|
+
length = rb_intern("length");
|
257
297
|
}
|
258
298
|
|
259
|
-
|
299
|
+
// The secondary map is a regular Hash, and will never shrink on its own.
|
300
|
+
// The main object cache is a WeakMap that will automatically remove entries
|
301
|
+
// when the target object is no longer reachable, but unless we manually
|
302
|
+
// remove the corresponding entries from the secondary map, it will grow
|
303
|
+
// without bound.
|
304
|
+
//
|
305
|
+
// To avoid this unbounded growth we periodically remove entries from the
|
306
|
+
// secondary map that are no longer present in the WeakMap. The logic of
|
307
|
+
// how often to perform this GC is an artbirary tuning parameter that
|
308
|
+
// represents a straightforward CPU/memory tradeoff.
|
309
|
+
//
|
310
|
+
// Requires: secondary_map_mutex is held.
|
311
|
+
static void SecondaryMap_MaybeGC() {
|
312
|
+
PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
313
|
+
size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
|
314
|
+
size_t secondary_len = RHASH_SIZE(secondary_map);
|
315
|
+
if (secondary_len < weak_len) {
|
316
|
+
// Logically this case should not be possible: a valid entry cannot exist in
|
317
|
+
// the weak table unless there is a corresponding entry in the secondary
|
318
|
+
// table. It should *always* be the case that secondary_len >= weak_len.
|
319
|
+
//
|
320
|
+
// However ObjectSpace::WeakMap#length (and therefore weak_len) is
|
321
|
+
// unreliable: it overreports its true length by including non-live objects.
|
322
|
+
// However these non-live objects are not yielded in iteration, so we may
|
323
|
+
// have previously deleted them from the secondary map in a previous
|
324
|
+
// invocation of SecondaryMap_MaybeGC().
|
325
|
+
//
|
326
|
+
// In this case, we can't measure any waste, so we just return.
|
327
|
+
return;
|
328
|
+
}
|
329
|
+
size_t waste = secondary_len - weak_len;
|
330
|
+
// GC if we could remove at least 2000 entries or 20% of the table size
|
331
|
+
// (whichever is greater). Since the cost of the GC pass is O(N), we
|
332
|
+
// want to make sure that we condition this on overall table size, to
|
333
|
+
// avoid O(N^2) CPU costs.
|
334
|
+
size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
|
335
|
+
if (waste > threshold) {
|
336
|
+
rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2,
|
337
|
+
secondary_map, weak_obj_cache);
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
342
|
+
static VALUE SecondaryMap_Get(VALUE key, bool create) {
|
343
|
+
PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
260
344
|
VALUE ret = rb_hash_lookup(secondary_map, key);
|
261
|
-
if (ret == Qnil) {
|
262
|
-
|
345
|
+
if (ret == Qnil && create) {
|
346
|
+
SecondaryMap_MaybeGC();
|
347
|
+
ret = rb_class_new_instance(0, NULL, rb_cObject);
|
263
348
|
rb_hash_aset(secondary_map, key, ret);
|
264
349
|
}
|
265
350
|
return ret;
|
@@ -267,14 +352,13 @@ static VALUE SecondaryMap_Get(VALUE key) {
|
|
267
352
|
|
268
353
|
#endif
|
269
354
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
VALUE ret = LL2NUM(key_int >> 2);
|
355
|
+
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
356
|
+
static VALUE ObjectCache_GetKey(const void* key, bool create) {
|
357
|
+
VALUE key_val = (VALUE)key;
|
358
|
+
PBRUBY_ASSERT((key_val & 3) == 0);
|
359
|
+
VALUE ret = LL2NUM(key_val >> 2);
|
276
360
|
#if USE_SECONDARY_MAP
|
277
|
-
ret = SecondaryMap_Get(ret);
|
361
|
+
ret = SecondaryMap_Get(ret, create);
|
278
362
|
#endif
|
279
363
|
return ret;
|
280
364
|
}
|
@@ -298,14 +382,20 @@ static void ObjectCache_Init() {
|
|
298
382
|
|
299
383
|
void ObjectCache_Add(const void* key, VALUE val) {
|
300
384
|
PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
|
301
|
-
|
385
|
+
#if USE_SECONDARY_MAP
|
386
|
+
rb_mutex_lock(secondary_map_mutex);
|
387
|
+
#endif
|
388
|
+
VALUE key_rb = ObjectCache_GetKey(key, true);
|
302
389
|
rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
|
390
|
+
#if USE_SECONDARY_MAP
|
391
|
+
rb_mutex_unlock(secondary_map_mutex);
|
392
|
+
#endif
|
303
393
|
PBRUBY_ASSERT(ObjectCache_Get(key) == val);
|
304
394
|
}
|
305
395
|
|
306
396
|
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
307
397
|
VALUE ObjectCache_Get(const void* key) {
|
308
|
-
VALUE key_rb = ObjectCache_GetKey(key);
|
398
|
+
VALUE key_rb = ObjectCache_GetKey(key, false);
|
309
399
|
return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
|
310
400
|
}
|
311
401
|
|
@@ -368,8 +458,10 @@ void Init_protobuf_c() {
|
|
368
458
|
Map_register(protobuf);
|
369
459
|
Message_register(protobuf);
|
370
460
|
|
371
|
-
|
461
|
+
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
|
462
|
+
rb_gc_register_mark_object(cParseError);
|
372
463
|
cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
|
464
|
+
rb_gc_register_mark_object(cTypeError);
|
373
465
|
|
374
466
|
rb_define_singleton_method(protobuf, "discard_unknown",
|
375
467
|
Google_Protobuf_discard_unknown, 1);
|
@@ -55,6 +55,10 @@ const upb_fielddef* map_field_value(const upb_fielddef* field);
|
|
55
55
|
VALUE Arena_new();
|
56
56
|
upb_arena *Arena_get(VALUE arena);
|
57
57
|
|
58
|
+
// Fuses this arena to another, throwing a Ruby exception if this is not
|
59
|
+
// possible.
|
60
|
+
void Arena_fuse(VALUE arena, upb_arena *other);
|
61
|
+
|
58
62
|
// Pins this Ruby object to the lifetime of this arena, so that as long as the
|
59
63
|
// arena is alive this object will not be collected.
|
60
64
|
//
|
@@ -106,6 +110,8 @@ extern VALUE cTypeError;
|
|
106
110
|
#define PBRUBY_ASSERT(expr) assert(expr)
|
107
111
|
#endif
|
108
112
|
|
113
|
+
#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
|
114
|
+
|
109
115
|
#define UPB_UNUSED(var) (void)var
|
110
116
|
|
111
117
|
#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
@@ -149,7 +149,8 @@ VALUE RepeatedField_deep_copy(VALUE _self) {
|
|
149
149
|
return new_rptfield;
|
150
150
|
}
|
151
151
|
|
152
|
-
const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef
|
152
|
+
const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef* field,
|
153
|
+
upb_arena* arena) {
|
153
154
|
RepeatedField* self;
|
154
155
|
TypeInfo type_info = TypeInfo_get(field);
|
155
156
|
|
@@ -167,6 +168,7 @@ const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef *field)
|
|
167
168
|
rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
|
168
169
|
}
|
169
170
|
|
171
|
+
Arena_fuse(self->arena, arena);
|
170
172
|
return self->array;
|
171
173
|
}
|
172
174
|
|
@@ -412,7 +414,7 @@ static VALUE RepeatedField_dup(VALUE _self) {
|
|
412
414
|
int size = upb_array_size(self->array);
|
413
415
|
int i;
|
414
416
|
|
415
|
-
|
417
|
+
Arena_fuse(self->arena, arena);
|
416
418
|
|
417
419
|
for (i = 0; i < size; i++) {
|
418
420
|
upb_msgval msgval = upb_array_get(self->array, i);
|
@@ -44,7 +44,8 @@ VALUE RepeatedField_GetRubyWrapper(upb_array* msg, TypeInfo type_info,
|
|
44
44
|
// Gets the underlying upb_array for this Ruby RepeatedField object, which must
|
45
45
|
// have a type that matches |f|. If this is not a repeated field or the type
|
46
46
|
// doesn't match, raises an exception.
|
47
|
-
const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f
|
47
|
+
const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f,
|
48
|
+
upb_arena* arena);
|
48
49
|
|
49
50
|
// Implements #inspect for this repeated field by appending its contents to |b|.
|
50
51
|
void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,
|