google-protobuf 3.15.6 → 3.17.3
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 +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,
|