google-protobuf 3.23.4 → 3.25.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +23 -70
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +153 -40
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +2 -1
  8. data/ext/google/protobuf_c/glue.c +56 -0
  9. data/ext/google/protobuf_c/map.c +27 -28
  10. data/ext/google/protobuf_c/map.h +6 -28
  11. data/ext/google/protobuf_c/message.c +70 -78
  12. data/ext/google/protobuf_c/message.h +10 -28
  13. data/ext/google/protobuf_c/protobuf.c +35 -174
  14. data/ext/google/protobuf_c/protobuf.h +24 -32
  15. data/ext/google/protobuf_c/repeated_field.c +28 -29
  16. data/ext/google/protobuf_c/repeated_field.h +6 -28
  17. data/ext/google/protobuf_c/ruby-upb.c +4451 -4011
  18. data/ext/google/protobuf_c/ruby-upb.h +5130 -3866
  19. data/ext/google/protobuf_c/shared_convert.c +64 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +65 -0
  22. data/ext/google/protobuf_c/shared_message.h +25 -0
  23. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  24. data/lib/google/protobuf/any_pb.rb +1 -1
  25. data/lib/google/protobuf/api_pb.rb +1 -1
  26. data/lib/google/protobuf/descriptor_pb.rb +13 -2
  27. data/lib/google/protobuf/duration_pb.rb +1 -1
  28. data/lib/google/protobuf/empty_pb.rb +1 -1
  29. data/lib/google/protobuf/ffi/descriptor.rb +165 -0
  30. data/lib/google/protobuf/ffi/descriptor_pool.rb +75 -0
  31. data/lib/google/protobuf/ffi/enum_descriptor.rb +171 -0
  32. data/lib/google/protobuf/ffi/ffi.rb +213 -0
  33. data/lib/google/protobuf/ffi/field_descriptor.rb +319 -0
  34. data/lib/google/protobuf/ffi/file_descriptor.rb +59 -0
  35. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  36. data/lib/google/protobuf/ffi/internal/convert.rb +305 -0
  37. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  38. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  39. data/lib/google/protobuf/ffi/map.rb +407 -0
  40. data/lib/google/protobuf/ffi/message.rb +662 -0
  41. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  42. data/lib/google/protobuf/ffi/oneof_descriptor.rb +95 -0
  43. data/lib/google/protobuf/ffi/repeated_field.rb +383 -0
  44. data/lib/google/protobuf/field_mask_pb.rb +1 -1
  45. data/lib/google/protobuf/message_exts.rb +3 -26
  46. data/lib/google/protobuf/object_cache.rb +97 -0
  47. data/lib/google/protobuf/plugin_pb.rb +2 -2
  48. data/lib/google/protobuf/repeated_field.rb +3 -26
  49. data/lib/google/protobuf/source_context_pb.rb +1 -1
  50. data/lib/google/protobuf/struct_pb.rb +1 -1
  51. data/lib/google/protobuf/timestamp_pb.rb +1 -1
  52. data/lib/google/protobuf/type_pb.rb +1 -1
  53. data/lib/google/protobuf/well_known_types.rb +5 -34
  54. data/lib/google/protobuf/wrappers_pb.rb +1 -1
  55. data/lib/google/protobuf.rb +27 -45
  56. data/lib/google/protobuf_ffi.rb +50 -0
  57. data/lib/google/protobuf_native.rb +20 -0
  58. data/lib/google/tasks/ffi.rake +102 -0
  59. metadata +72 -4
@@ -1,32 +1,9 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #include "protobuf.h"
32
9
 
@@ -195,7 +172,8 @@ const rb_data_type_t Arena_type = {
195
172
  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
196
173
  };
197
174
 
198
- static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size) {
175
+ static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
176
+ size_t size) {
199
177
  if (size == 0) {
200
178
  xfree(ptr);
201
179
  return NULL;
@@ -252,164 +230,48 @@ void Arena_register(VALUE module) {
252
230
  // Object Cache
253
231
  // -----------------------------------------------------------------------------
254
232
 
255
- // A pointer -> Ruby Object cache that keeps references to Ruby wrapper
256
- // objects. This allows us to look up any Ruby wrapper object by the address
257
- // of the object it is wrapping. That way we can avoid ever creating two
258
- // different wrapper objects for the same C object, which saves memory and
259
- // preserves object identity.
260
- //
261
- // We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
262
- // to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
263
- // keys.
264
- //
265
- // We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
266
- // means it may not be possible to fit a pointer into a Fixnum. Keys are
267
- // pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
268
- // they overflow and require allocating a Bignum, they could get collected
269
- // prematurely, thus removing the cache entry. This happens on 64-bit Windows,
270
- // on which pointers are 64 bits but longs are 32 bits. In this case, we enable
271
- // the secondary Hash to hold the keys and prevent them from being collected.
272
-
273
- #if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
274
- #define USE_SECONDARY_MAP 0
275
- #else
276
- #define USE_SECONDARY_MAP 1
277
- #endif
278
-
279
- #if USE_SECONDARY_MAP
280
-
281
- // Maps Numeric -> Object. The object is then used as a key into the WeakMap.
282
- // This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
283
- // The object is used only for its identity; it does not contain any data.
284
- VALUE secondary_map = Qnil;
285
-
286
- // Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
287
- // iterates over the map which cannot happen in parallel with insertions, or
288
- // Ruby will throw:
289
- // can't add a new key into hash during iteration (RuntimeError)
290
- VALUE secondary_map_mutex = Qnil;
291
-
292
- // Lambda that will GC entries from the secondary map that are no longer present
293
- // in the primary map.
294
- VALUE gc_secondary_map_lambda = Qnil;
295
- ID length;
296
-
297
- extern VALUE weak_obj_cache;
298
-
299
- static void SecondaryMap_Init() {
300
- rb_gc_register_address(&secondary_map);
301
- rb_gc_register_address(&gc_secondary_map_lambda);
302
- rb_gc_register_address(&secondary_map_mutex);
303
- secondary_map = rb_hash_new();
304
- gc_secondary_map_lambda = rb_eval_string(
305
- "->(secondary, weak) {\n"
306
- " secondary.delete_if { |k, v| !weak.key?(v) }\n"
307
- "}\n");
308
- secondary_map_mutex = rb_mutex_new();
309
- length = rb_intern("length");
310
- }
311
-
312
- // The secondary map is a regular Hash, and will never shrink on its own.
313
- // The main object cache is a WeakMap that will automatically remove entries
314
- // when the target object is no longer reachable, but unless we manually
315
- // remove the corresponding entries from the secondary map, it will grow
316
- // without bound.
317
- //
318
- // To avoid this unbounded growth we periodically remove entries from the
319
- // secondary map that are no longer present in the WeakMap. The logic of
320
- // how often to perform this GC is an artbirary tuning parameter that
321
- // represents a straightforward CPU/memory tradeoff.
322
- //
323
- // Requires: secondary_map_mutex is held.
324
- static void SecondaryMap_MaybeGC() {
325
- PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
326
- size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
327
- size_t secondary_len = RHASH_SIZE(secondary_map);
328
- if (secondary_len < weak_len) {
329
- // Logically this case should not be possible: a valid entry cannot exist in
330
- // the weak table unless there is a corresponding entry in the secondary
331
- // table. It should *always* be the case that secondary_len >= weak_len.
332
- //
333
- // However ObjectSpace::WeakMap#length (and therefore weak_len) is
334
- // unreliable: it overreports its true length by including non-live objects.
335
- // However these non-live objects are not yielded in iteration, so we may
336
- // have previously deleted them from the secondary map in a previous
337
- // invocation of SecondaryMap_MaybeGC().
338
- //
339
- // In this case, we can't measure any waste, so we just return.
340
- return;
341
- }
342
- size_t waste = secondary_len - weak_len;
343
- // GC if we could remove at least 2000 entries or 20% of the table size
344
- // (whichever is greater). Since the cost of the GC pass is O(N), we
345
- // want to make sure that we condition this on overall table size, to
346
- // avoid O(N^2) CPU costs.
347
- size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
348
- if (waste > threshold) {
349
- rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2, secondary_map,
350
- weak_obj_cache);
351
- }
352
- }
353
-
354
- // Requires: secondary_map_mutex is held by this thread iff create == true.
355
- static VALUE SecondaryMap_Get(VALUE key, bool create) {
356
- PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
357
- VALUE ret = rb_hash_lookup(secondary_map, key);
358
- if (ret == Qnil && create) {
359
- SecondaryMap_MaybeGC();
360
- ret = rb_class_new_instance(0, NULL, rb_cObject);
361
- rb_hash_aset(secondary_map, key, ret);
362
- }
363
- return ret;
364
- }
365
-
366
- #endif
367
-
368
- // Requires: secondary_map_mutex is held by this thread iff create == true.
369
- static VALUE ObjectCache_GetKey(const void *key, bool create) {
370
- VALUE key_val = (VALUE)key;
371
- PBRUBY_ASSERT((key_val & 3) == 0);
372
- VALUE ret = LL2NUM(key_val >> 2);
373
- #if USE_SECONDARY_MAP
374
- ret = SecondaryMap_Get(ret, create);
375
- #endif
376
- return ret;
377
- }
378
-
379
233
  // Public ObjectCache API.
380
234
 
381
235
  VALUE weak_obj_cache = Qnil;
382
236
  ID item_get;
383
- ID item_set;
237
+ ID item_try_add;
238
+
239
+ static void ObjectCache_Init(VALUE protobuf) {
240
+ item_get = rb_intern("get");
241
+ item_try_add = rb_intern("try_add");
384
242
 
385
- static void ObjectCache_Init() {
386
243
  rb_gc_register_address(&weak_obj_cache);
387
- VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
388
- weak_obj_cache = rb_class_new_instance(0, NULL, klass);
389
- item_get = rb_intern("[]");
390
- item_set = rb_intern("[]=");
391
- #if USE_SECONDARY_MAP
392
- SecondaryMap_Init();
244
+ #if SIZEOF_LONG >= SIZEOF_VALUE
245
+ VALUE cache_class = rb_const_get(protobuf, rb_intern("ObjectCache"));
246
+ #else
247
+ VALUE cache_class = rb_const_get(protobuf, rb_intern("LegacyObjectCache"));
393
248
  #endif
249
+
250
+ weak_obj_cache = rb_class_new_instance(0, NULL, cache_class);
251
+ rb_const_set(protobuf, rb_intern("OBJECT_CACHE"), weak_obj_cache);
252
+ rb_const_set(protobuf, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG));
253
+ rb_const_set(protobuf, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE));
394
254
  }
395
255
 
396
- void ObjectCache_Add(const void *key, VALUE val) {
397
- PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
398
- #if USE_SECONDARY_MAP
399
- rb_mutex_lock(secondary_map_mutex);
400
- #endif
401
- VALUE key_rb = ObjectCache_GetKey(key, true);
402
- rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
403
- #if USE_SECONDARY_MAP
404
- rb_mutex_unlock(secondary_map_mutex);
405
- #endif
406
- PBRUBY_ASSERT(ObjectCache_Get(key) == val);
256
+ static VALUE ObjectCache_GetKey(const void *key) {
257
+ VALUE key_val = (VALUE)key;
258
+ PBRUBY_ASSERT((key_val & 3) == 0);
259
+ // Ensure the key can be stored as a Fixnum since 1 bit is needed for
260
+ // FIXNUM_FLAG and 1 bit is needed for the sign bit.
261
+ VALUE new_key = LL2NUM(key_val >> 2);
262
+ PBRUBY_ASSERT(FIXNUM_P(new_key));
263
+ return new_key;
264
+ }
265
+
266
+ VALUE ObjectCache_TryAdd(const void *key, VALUE val) {
267
+ VALUE key_val = ObjectCache_GetKey(key);
268
+ return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val);
407
269
  }
408
270
 
409
271
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
410
272
  VALUE ObjectCache_Get(const void *key) {
411
- VALUE key_rb = ObjectCache_GetKey(key, false);
412
- return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
273
+ VALUE key_val = ObjectCache_GetKey(key);
274
+ return rb_funcall(weak_obj_cache, item_get, 1, key_val);
413
275
  }
414
276
 
415
277
  /*
@@ -459,11 +321,10 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
459
321
  // This must be named "Init_protobuf_c" because the Ruby module is named
460
322
  // "protobuf_c" -- the VM looks for this symbol in our .so.
461
323
  __attribute__((visibility("default"))) void Init_protobuf_c() {
462
- ObjectCache_Init();
463
-
464
324
  VALUE google = rb_define_module("Google");
465
325
  VALUE protobuf = rb_define_module_under(google, "Protobuf");
466
326
 
327
+ ObjectCache_Init(protobuf);
467
328
  Arena_register(protobuf);
468
329
  Defs_register(protobuf);
469
330
  RepeatedField_register(protobuf);
@@ -1,38 +1,29 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
32
9
  #define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
33
10
 
11
+ // Ruby 3+ defines NDEBUG itself, see: https://bugs.ruby-lang.org/issues/18777
12
+ #ifdef NDEBUG
13
+ #include <ruby.h>
14
+ #else
15
+ #include <ruby.h>
16
+ #undef NDEBUG
17
+ #endif
18
+
19
+ #include <ruby/version.h>
20
+
21
+ #if RUBY_API_VERSION_CODE < 20700
22
+ #error Protobuf requires Ruby >= 2.7
23
+ #endif
24
+
25
+ #include <assert.h> // Must be included after the NDEBUG logic above.
34
26
  #include <ruby/encoding.h>
35
- #include <ruby/ruby.h>
36
27
  #include <ruby/vm.h>
37
28
 
38
29
  #include "defs.h"
@@ -76,10 +67,9 @@ void Arena_Pin(VALUE arena, VALUE obj);
76
67
  // being collected (though in Ruby <2.7 is it effectively strong, due to
77
68
  // implementation limitations).
78
69
 
79
- // Adds an entry to the cache. The "arena" parameter must give the arena that
80
- // "key" was allocated from. In Ruby <2.7.0, it will be used to remove the key
81
- // from the cache when the arena is destroyed.
82
- void ObjectCache_Add(const void* key, VALUE val);
70
+ // Tries to add a new entry to the cache, returning the newly installed value or
71
+ // the pre-existing entry.
72
+ VALUE ObjectCache_TryAdd(const void* key, VALUE val);
83
73
 
84
74
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
85
75
  VALUE ObjectCache_Get(const void* key);
@@ -110,7 +100,9 @@ extern VALUE cTypeError;
110
100
  do { \
111
101
  } while (false && (expr))
112
102
  #else
113
- #define PBRUBY_ASSERT(expr) assert(expr)
103
+ #define PBRUBY_ASSERT(expr) \
104
+ if (!(expr)) \
105
+ rb_bug("Assertion failed at %s:%d, expr: %s", __FILE__, __LINE__, #expr)
114
106
  #endif
115
107
 
116
108
  #define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
@@ -1,32 +1,9 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2014 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #include "repeated_field.h"
32
9
 
@@ -87,7 +64,6 @@ VALUE RepeatedField_GetRubyWrapper(upb_Array* array, TypeInfo type_info,
87
64
  if (val == Qnil) {
88
65
  val = RepeatedField_alloc(cRepeatedField);
89
66
  RepeatedField* self;
90
- ObjectCache_Add(array, val);
91
67
  TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
92
68
  self->array = array;
93
69
  self->arena = arena;
@@ -95,11 +71,14 @@ VALUE RepeatedField_GetRubyWrapper(upb_Array* array, TypeInfo type_info,
95
71
  if (self->type_info.type == kUpb_CType_Message) {
96
72
  self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
97
73
  }
74
+ val = ObjectCache_TryAdd(array, val);
98
75
  }
99
76
 
100
77
  PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type);
101
78
  PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef ==
102
79
  type_info.def.msgdef);
80
+ PBRUBY_ASSERT(ruby_to_RepeatedField(val)->array == array);
81
+
103
82
  return val;
104
83
  }
105
84
 
@@ -284,7 +263,7 @@ static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
284
263
  memset(&fill, 0, sizeof(fill));
285
264
  for (int i = size; i < index; i++) {
286
265
  // Fill default values.
287
- // TODO(haberman): should this happen at the upb level?
266
+ // TODO: should this happen at the upb level?
288
267
  upb_Array_Set(array, i, fill);
289
268
  }
290
269
  }
@@ -508,6 +487,25 @@ static VALUE RepeatedField_freeze(VALUE _self) {
508
487
  return _self;
509
488
  }
510
489
 
490
+ /*
491
+ * Deep freezes the repeated field and values recursively.
492
+ * Internal use only.
493
+ */
494
+ VALUE RepeatedField_internal_deep_freeze(VALUE _self) {
495
+ RepeatedField* self = ruby_to_RepeatedField(_self);
496
+ RepeatedField_freeze(_self);
497
+ if (self->type_info.type == kUpb_CType_Message) {
498
+ int size = upb_Array_Size(self->array);
499
+ int i;
500
+ for (i = 0; i < size; i++) {
501
+ upb_MessageValue msgval = upb_Array_Get(self->array, i);
502
+ VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
503
+ Message_internal_deep_freeze(val);
504
+ }
505
+ }
506
+ return _self;
507
+ }
508
+
511
509
  /*
512
510
  * call-seq:
513
511
  * RepeatedField.hash => hash_value
@@ -613,7 +611,8 @@ VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
613
611
 
614
612
  self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
615
613
  self->array = upb_Array_New(arena, self->type_info.type);
616
- ObjectCache_Add(self->array, _self);
614
+ VALUE stored_val = ObjectCache_TryAdd(self->array, _self);
615
+ PBRUBY_ASSERT(stored_val == _self);
617
616
 
618
617
  if (ary != Qnil) {
619
618
  if (!RB_TYPE_P(ary, T_ARRAY)) {
@@ -1,38 +1,13 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2008 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #ifndef RUBY_PROTOBUF_REPEATED_FIELD_H_
32
9
  #define RUBY_PROTOBUF_REPEATED_FIELD_H_
33
10
 
34
- #include <ruby/ruby.h>
35
-
36
11
  #include "protobuf.h"
37
12
  #include "ruby-upb.h"
38
13
 
@@ -60,4 +35,7 @@ extern VALUE cRepeatedField;
60
35
  // Call at startup to register all types in this module.
61
36
  void RepeatedField_register(VALUE module);
62
37
 
38
+ // Recursively freeze RepeatedField.
39
+ VALUE RepeatedField_internal_deep_freeze(VALUE _self);
40
+
63
41
  #endif // RUBY_PROTOBUF_REPEATED_FIELD_H_