google-protobuf 3.25.8 → 4.32.1

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +33 -15
  3. data/ext/google/protobuf_c/defs.c +802 -125
  4. data/ext/google/protobuf_c/extconf.rb +20 -10
  5. data/ext/google/protobuf_c/glue.c +79 -0
  6. data/ext/google/protobuf_c/map.c +145 -63
  7. data/ext/google/protobuf_c/map.h +7 -3
  8. data/ext/google/protobuf_c/message.c +204 -171
  9. data/ext/google/protobuf_c/message.h +2 -6
  10. data/ext/google/protobuf_c/protobuf.c +33 -19
  11. data/ext/google/protobuf_c/protobuf.h +3 -15
  12. data/ext/google/protobuf_c/repeated_field.c +130 -58
  13. data/ext/google/protobuf_c/repeated_field.h +6 -2
  14. data/ext/google/protobuf_c/ruby-upb.c +10324 -7764
  15. data/ext/google/protobuf_c/ruby-upb.h +9959 -6442
  16. data/ext/google/protobuf_c/shared_convert.c +7 -2
  17. data/ext/google/protobuf_c/shared_message.c +3 -32
  18. data/ext/google/protobuf_c/shared_message.h +0 -4
  19. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +207 -0
  20. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
  21. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
  22. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
  23. data/lib/google/protobuf/any_pb.rb +2 -23
  24. data/lib/google/protobuf/api_pb.rb +3 -26
  25. data/lib/google/protobuf/descriptor_pb.rb +8 -24
  26. data/lib/google/protobuf/duration_pb.rb +2 -23
  27. data/lib/google/protobuf/empty_pb.rb +2 -23
  28. data/lib/google/protobuf/ffi/descriptor.rb +14 -4
  29. data/lib/google/protobuf/ffi/descriptor_pool.rb +5 -1
  30. data/lib/google/protobuf/ffi/enum_descriptor.rb +13 -1
  31. data/lib/google/protobuf/ffi/ffi.rb +7 -6
  32. data/lib/google/protobuf/ffi/field_descriptor.rb +29 -2
  33. data/lib/google/protobuf/ffi/file_descriptor.rb +39 -13
  34. data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
  35. data/lib/google/protobuf/ffi/internal/convert.rb +17 -30
  36. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +2 -1
  37. data/lib/google/protobuf/ffi/map.rb +52 -26
  38. data/lib/google/protobuf/ffi/message.rb +188 -67
  39. data/lib/google/protobuf/ffi/method_descriptor.rb +124 -0
  40. data/lib/google/protobuf/ffi/object_cache.rb +3 -3
  41. data/lib/google/protobuf/ffi/oneof_descriptor.rb +13 -1
  42. data/lib/google/protobuf/ffi/repeated_field.rb +47 -19
  43. data/lib/google/protobuf/ffi/service_descriptor.rb +117 -0
  44. data/lib/google/protobuf/field_mask_pb.rb +2 -23
  45. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  46. data/lib/google/protobuf/message_exts.rb +4 -0
  47. data/lib/google/protobuf/plugin_pb.rb +3 -25
  48. data/lib/google/protobuf/repeated_field.rb +4 -5
  49. data/lib/google/protobuf/source_context_pb.rb +2 -23
  50. data/lib/google/protobuf/struct_pb.rb +2 -23
  51. data/lib/google/protobuf/timestamp_pb.rb +2 -23
  52. data/lib/google/protobuf/type_pb.rb +2 -25
  53. data/lib/google/protobuf/wrappers_pb.rb +2 -23
  54. data/lib/google/protobuf.rb +1 -1
  55. data/lib/google/protobuf_ffi.rb +6 -4
  56. data/lib/google/protobuf_native.rb +0 -1
  57. data/lib/google/tasks/ffi.rake +2 -4
  58. metadata +36 -22
  59. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  60. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  61. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  62. data/ext/google/protobuf_c/wrap_memcpy.c +0 -29
  63. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  64. data/lib/google/protobuf/object_cache.rb +0 -97
@@ -6,23 +6,33 @@ ext_name = "google/protobuf_c"
6
6
 
7
7
  dir_config(ext_name)
8
8
 
9
- if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/
10
- $CFLAGS += " -std=gnu99 -O3 -DNDEBUG -fvisibility=hidden -Wall -Wsign-compare -Wno-declaration-after-statement"
11
- else
12
- $CFLAGS += " -std=gnu99 -O3 -DNDEBUG"
9
+ if ENV["CC"]
10
+ RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"]
11
+ end
12
+
13
+ if ENV["CXX"]
14
+ RbConfig::CONFIG["CXX"] = RbConfig::MAKEFILE_CONFIG["CXX"] = ENV["CXX"]
15
+ end
16
+
17
+ if ENV["LD"]
18
+ RbConfig::CONFIG["LD"] = RbConfig::MAKEFILE_CONFIG["LD"] = ENV["LD"]
13
19
  end
14
20
 
15
- if RUBY_PLATFORM =~ /linux/
16
- # Instruct the linker to point memcpy calls at our __wrap_memcpy wrapper.
17
- $LDFLAGS += " -Wl,-wrap,memcpy"
21
+ debug_enabled = ENV["PROTOBUF_CONFIG"] == "dbg"
22
+
23
+ additional_c_flags = debug_enabled ? "-O0 -fno-omit-frame-pointer -fvisibility=default -g" : "-O3 -DNDEBUG -fvisibility=hidden"
24
+
25
+ if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/
26
+ $CFLAGS += " -std=gnu99 -Wall -Wsign-compare -Wno-declaration-after-statement #{additional_c_flags}"
27
+ else
28
+ $CFLAGS += " -std=gnu99 #{additional_c_flags}"
18
29
  end
19
30
 
20
31
  $VPATH << "$(srcdir)/third_party/utf8_range"
21
32
  $INCFLAGS += " -I$(srcdir)/third_party/utf8_range"
22
33
 
23
- $srcs = ["protobuf.c", "convert.c", "defs.c", "message.c",
24
- "repeated_field.c", "map.c", "ruby-upb.c", "wrap_memcpy.c",
25
- "naive.c", "range2-neon.c", "range2-sse.c", "shared_convert.c",
34
+ $srcs = ["protobuf.c", "convert.c", "defs.c", "message.c", "repeated_field.c",
35
+ "map.c", "ruby-upb.c", "utf8_range.c", "shared_convert.c",
26
36
  "shared_message.c"]
27
37
 
28
38
  create_makefile(ext_name)
@@ -26,6 +26,15 @@ char* EnumDescriptor_serialized_options(const upb_EnumDef* enumdef,
26
26
  return serialized;
27
27
  }
28
28
 
29
+ char* EnumDescriptor_serialized_to_proto(const upb_EnumDef* enumdef,
30
+ size_t* size, upb_Arena* arena) {
31
+ const google_protobuf_EnumDescriptorProto* file_proto =
32
+ upb_EnumDef_ToProto(enumdef, arena);
33
+ char* serialized =
34
+ google_protobuf_EnumDescriptorProto_serialize(file_proto, arena, size);
35
+ return serialized;
36
+ }
37
+
29
38
  char* FileDescriptor_serialized_options(const upb_FileDef* filedef,
30
39
  size_t* size, upb_Arena* arena) {
31
40
  const google_protobuf_FileOptions* opts = upb_FileDef_Options(filedef);
@@ -33,6 +42,15 @@ char* FileDescriptor_serialized_options(const upb_FileDef* filedef,
33
42
  return serialized;
34
43
  }
35
44
 
45
+ char* FileDescriptor_serialized_to_proto(const upb_FileDef* filedef,
46
+ size_t* size, upb_Arena* arena) {
47
+ const google_protobuf_FileDescriptorProto* file_proto =
48
+ upb_FileDef_ToProto(filedef, arena);
49
+ char* serialized =
50
+ google_protobuf_FileDescriptorProto_serialize(file_proto, arena, size);
51
+ return serialized;
52
+ }
53
+
36
54
  char* Descriptor_serialized_options(const upb_MessageDef* msgdef, size_t* size,
37
55
  upb_Arena* arena) {
38
56
  const google_protobuf_MessageOptions* opts = upb_MessageDef_Options(msgdef);
@@ -41,6 +59,15 @@ char* Descriptor_serialized_options(const upb_MessageDef* msgdef, size_t* size,
41
59
  return serialized;
42
60
  }
43
61
 
62
+ char* Descriptor_serialized_to_proto(const upb_MessageDef* msgdef, size_t* size,
63
+ upb_Arena* arena) {
64
+ const google_protobuf_DescriptorProto* proto =
65
+ upb_MessageDef_ToProto(msgdef, arena);
66
+ char* serialized =
67
+ google_protobuf_DescriptorProto_serialize(proto, arena, size);
68
+ return serialized;
69
+ }
70
+
44
71
  char* OneOfDescriptor_serialized_options(const upb_OneofDef* oneofdef,
45
72
  size_t* size, upb_Arena* arena) {
46
73
  const google_protobuf_OneofOptions* opts = upb_OneofDef_Options(oneofdef);
@@ -48,9 +75,61 @@ char* OneOfDescriptor_serialized_options(const upb_OneofDef* oneofdef,
48
75
  return serialized;
49
76
  }
50
77
 
78
+ char* OneOfDescriptor_serialized_to_proto(const upb_OneofDef* oneofdef,
79
+ size_t* size, upb_Arena* arena) {
80
+ const google_protobuf_OneofDescriptorProto* proto =
81
+ upb_OneofDef_ToProto(oneofdef, arena);
82
+ char* serialized =
83
+ google_protobuf_OneofDescriptorProto_serialize(proto, arena, size);
84
+ return serialized;
85
+ }
86
+
51
87
  char* FieldDescriptor_serialized_options(const upb_FieldDef* fielddef,
52
88
  size_t* size, upb_Arena* arena) {
53
89
  const google_protobuf_FieldOptions* opts = upb_FieldDef_Options(fielddef);
54
90
  char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, size);
55
91
  return serialized;
56
92
  }
93
+
94
+ char* FieldDescriptor_serialized_to_proto(const upb_FieldDef* fieldef,
95
+ size_t* size, upb_Arena* arena) {
96
+ const google_protobuf_FieldDescriptorProto* proto =
97
+ upb_FieldDef_ToProto(fieldef, arena);
98
+ char* serialized =
99
+ google_protobuf_FieldDescriptorProto_serialize(proto, arena, size);
100
+ return serialized;
101
+ }
102
+
103
+ char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef,
104
+ size_t* size, upb_Arena* arena) {
105
+ const google_protobuf_ServiceOptions* opts =
106
+ upb_ServiceDef_Options(servicedef);
107
+ char* serialized =
108
+ google_protobuf_ServiceOptions_serialize(opts, arena, size);
109
+ return serialized;
110
+ }
111
+
112
+ char* ServiceDescriptor_serialized_to_proto(const upb_ServiceDef* servicedef,
113
+ size_t* size, upb_Arena* arena) {
114
+ const google_protobuf_ServiceDescriptorProto* proto =
115
+ upb_ServiceDef_ToProto(servicedef, arena);
116
+ char* serialized =
117
+ google_protobuf_ServiceDescriptorProto_serialize(proto, arena, size);
118
+ return serialized;
119
+ }
120
+
121
+ char* MethodDescriptor_serialized_options(const upb_MethodDef* methoddef,
122
+ size_t* size, upb_Arena* arena) {
123
+ const google_protobuf_MethodOptions* opts = upb_MethodDef_Options(methoddef);
124
+ char* serialized = google_protobuf_MethodOptions_serialize(opts, arena, size);
125
+ return serialized;
126
+ }
127
+
128
+ char* MethodDescriptor_serialized_to_proto(const upb_MethodDef* methodef,
129
+ size_t* size, upb_Arena* arena) {
130
+ const google_protobuf_MethodDescriptorProto* proto =
131
+ upb_MethodDef_ToProto(methodef, arena);
132
+ char* serialized =
133
+ google_protobuf_MethodDescriptorProto_serialize(proto, arena, size);
134
+ return serialized;
135
+ }
@@ -38,9 +38,11 @@ static void Map_mark(void* _self) {
38
38
  rb_gc_mark(self->arena);
39
39
  }
40
40
 
41
+ static size_t Map_memsize(const void* _self) { return sizeof(Map); }
42
+
41
43
  const rb_data_type_t Map_type = {
42
44
  "Google::Protobuf::Map",
43
- {Map_mark, RUBY_DEFAULT_FREE, NULL},
45
+ {Map_mark, RUBY_DEFAULT_FREE, Map_memsize},
44
46
  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
45
47
  };
46
48
 
@@ -61,9 +63,10 @@ static VALUE Map_alloc(VALUE klass) {
61
63
  return TypedData_Wrap_Struct(klass, &Map_type, self);
62
64
  }
63
65
 
64
- VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
65
- VALUE arena) {
66
+ VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
67
+ TypeInfo value_type, VALUE arena) {
66
68
  PBRUBY_ASSERT(map);
69
+ PBRUBY_ASSERT(arena != Qnil);
67
70
 
68
71
  VALUE val = ObjectCache_Get(map);
69
72
 
@@ -81,7 +84,6 @@ VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
81
84
  }
82
85
  return ObjectCache_TryAdd(map, val);
83
86
  }
84
-
85
87
  return val;
86
88
  }
87
89
 
@@ -103,8 +105,9 @@ static TypeInfo Map_keyinfo(Map* self) {
103
105
  }
104
106
 
105
107
  static upb_Map* Map_GetMutable(VALUE _self) {
106
- rb_check_frozen(_self);
107
- return (upb_Map*)ruby_to_Map(_self)->map;
108
+ const upb_Map* map = ruby_to_Map(_self)->map;
109
+ Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map));
110
+ return (upb_Map*)map;
108
111
  }
109
112
 
110
113
  VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
@@ -233,10 +236,15 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
233
236
  return _self;
234
237
  }
235
238
 
239
+ /**
240
+ * ruby-doc: Map
241
+ *
242
+ * This class represents a Protobuf Map. It is largely automatically transformed
243
+ * to and from a Ruby hash.
244
+ */
245
+
236
246
  /*
237
- * call-seq:
238
- * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
239
- * => new map
247
+ * ruby-doc: Map#initialize
240
248
  *
241
249
  * Allocates a new Map container. This constructor may be called with 2, 3, or 4
242
250
  * arguments. The first two arguments are always present and are symbols (taking
@@ -262,6 +270,13 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
262
270
  * shallow-copied into the new Map: the original map is unmodified, but
263
271
  * references to underlying objects will be shared if the value type is a
264
272
  * message type.
273
+ *
274
+ * @param key_type [Symbol]
275
+ * @param value_type [Symbol]
276
+ * @param value_typeclass [Class<AbstractMessage>,Module]
277
+ * @paramdefault value_typeclass nil
278
+ * @param init_hashmap [Hash,Map]
279
+ * @paramdefault init_hashmap {}
265
280
  */
266
281
  static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
267
282
  Map* self = ruby_to_Map(_self);
@@ -308,12 +323,14 @@ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
308
323
  }
309
324
 
310
325
  /*
311
- * call-seq:
312
- * Map.each(&block)
326
+ * ruby-doc: Map#each
313
327
  *
314
328
  * Invokes &block on each |key, value| pair in the map, in unspecified order.
315
329
  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
316
330
  * sequence.
331
+ *
332
+ * @yield [Object, Object]
333
+ * @return [nil]
317
334
  */
318
335
  static VALUE Map_each(VALUE _self) {
319
336
  Map* self = ruby_to_Map(_self);
@@ -330,10 +347,11 @@ static VALUE Map_each(VALUE _self) {
330
347
  }
331
348
 
332
349
  /*
333
- * call-seq:
334
- * Map.keys => [list_of_keys]
350
+ * ruby-doc: Map#keys
335
351
  *
336
352
  * Returns the list of keys contained in the map, in unspecified order.
353
+ *
354
+ * @return [Array<Object>]
337
355
  */
338
356
  static VALUE Map_keys(VALUE _self) {
339
357
  Map* self = ruby_to_Map(_self);
@@ -350,10 +368,11 @@ static VALUE Map_keys(VALUE _self) {
350
368
  }
351
369
 
352
370
  /*
353
- * call-seq:
354
- * Map.values => [list_of_values]
371
+ * ruby-doc: Map#values
355
372
  *
356
373
  * Returns the list of values contained in the map, in unspecified order.
374
+ *
375
+ * @return [Array<Object>]
357
376
  */
358
377
  static VALUE Map_values(VALUE _self) {
359
378
  Map* self = ruby_to_Map(_self);
@@ -370,11 +389,13 @@ static VALUE Map_values(VALUE _self) {
370
389
  }
371
390
 
372
391
  /*
373
- * call-seq:
374
- * Map.[](key) => value
392
+ * ruby-doc: Map#[]
375
393
  *
376
394
  * Accesses the element at the given key. Throws an exception if the key type is
377
395
  * incorrect. Returns nil when the key is not present in the map.
396
+ *
397
+ * @param key [Object]
398
+ * @return [Object]
378
399
  */
379
400
  static VALUE Map_index(VALUE _self, VALUE key) {
380
401
  Map* self = ruby_to_Map(_self);
@@ -390,12 +411,15 @@ static VALUE Map_index(VALUE _self, VALUE key) {
390
411
  }
391
412
 
392
413
  /*
393
- * call-seq:
394
- * Map.[]=(key, value) => value
414
+ * ruby-doc: Map#[]=
395
415
  *
396
416
  * Inserts or overwrites the value at the given key with the given new value.
397
417
  * Throws an exception if the key type is incorrect. Returns the new value that
398
418
  * was just inserted.
419
+ *
420
+ * @param key [Object]
421
+ * @param value [Object]
422
+ * @return [Object]
399
423
  */
400
424
  static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
401
425
  Map* self = ruby_to_Map(_self);
@@ -411,11 +435,13 @@ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
411
435
  }
412
436
 
413
437
  /*
414
- * call-seq:
415
- * Map.has_key?(key) => bool
438
+ * ruby-doc: Map#has_key?
416
439
  *
417
440
  * Returns true if the given key is present in the map. Throws an exception if
418
441
  * the key has the wrong type.
442
+ *
443
+ * @param key [Object]
444
+ * @return [Boolean]
419
445
  */
420
446
  static VALUE Map_has_key(VALUE _self, VALUE key) {
421
447
  Map* self = ruby_to_Map(_self);
@@ -430,21 +456,23 @@ static VALUE Map_has_key(VALUE _self, VALUE key) {
430
456
  }
431
457
 
432
458
  /*
433
- * call-seq:
434
- * Map.delete(key) => old_value
459
+ * ruby-doc: Map#delete
435
460
  *
436
461
  * Deletes the value at the given key, if any, returning either the old value or
437
462
  * nil if none was present. Throws an exception if the key is of the wrong type.
463
+ *
464
+ * @param key [Object]
465
+ * @return [Object]
438
466
  */
439
467
  static VALUE Map_delete(VALUE _self, VALUE key) {
468
+ upb_Map* map = Map_GetMutable(_self);
440
469
  Map* self = ruby_to_Map(_self);
441
- rb_check_frozen(_self);
442
470
 
443
471
  upb_MessageValue key_upb =
444
472
  Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
445
473
  upb_MessageValue val_upb;
446
474
 
447
- if (upb_Map_Delete(self->map, key_upb, &val_upb)) {
475
+ if (upb_Map_Delete(map, key_upb, &val_upb)) {
448
476
  return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
449
477
  } else {
450
478
  return Qnil;
@@ -452,10 +480,11 @@ static VALUE Map_delete(VALUE _self, VALUE key) {
452
480
  }
453
481
 
454
482
  /*
455
- * call-seq:
456
- * Map.clear
483
+ * ruby-doc: Map#clear
457
484
  *
458
485
  * Removes all entries from the map.
486
+ *
487
+ * @return [nil]
459
488
  */
460
489
  static VALUE Map_clear(VALUE _self) {
461
490
  upb_Map_Clear(Map_GetMutable(_self));
@@ -463,10 +492,11 @@ static VALUE Map_clear(VALUE _self) {
463
492
  }
464
493
 
465
494
  /*
466
- * call-seq:
467
- * Map.length
495
+ * ruby-doc: Map#length
468
496
  *
469
497
  * Returns the number of entries (key-value pairs) in the map.
498
+ *
499
+ * @return [Integer]
470
500
  */
471
501
  static VALUE Map_length(VALUE _self) {
472
502
  Map* self = ruby_to_Map(_self);
@@ -474,11 +504,12 @@ static VALUE Map_length(VALUE _self) {
474
504
  }
475
505
 
476
506
  /*
477
- * call-seq:
478
- * Map.dup => new_map
507
+ * ruby-doc: Map#dup
479
508
  *
480
509
  * Duplicates this map with a shallow copy. References to all non-primitive
481
510
  * element objects (e.g., submessages) are shared.
511
+ *
512
+ * @return [Map]
482
513
  */
483
514
  static VALUE Map_dup(VALUE _self) {
484
515
  Map* self = ruby_to_Map(_self);
@@ -499,8 +530,7 @@ static VALUE Map_dup(VALUE _self) {
499
530
  }
500
531
 
501
532
  /*
502
- * call-seq:
503
- * Map.==(other) => boolean
533
+ * ruby-doc: Map#==
504
534
  *
505
535
  * Compares this map to another. Maps are equal if they have identical key sets,
506
536
  * and for each key, the values in both maps compare equal. Elements are
@@ -510,6 +540,9 @@ static VALUE Map_dup(VALUE _self) {
510
540
  * Maps with dissimilar key types or value types/typeclasses are never equal,
511
541
  * even if value comparison (for example, between integers and floats) would
512
542
  * have otherwise indicated that every element has equal value.
543
+ *
544
+ * @param other [Map]
545
+ * @return [Boolean]
513
546
  */
514
547
  VALUE Map_eq(VALUE _self, VALUE _other) {
515
548
  Map* self = ruby_to_Map(_self);
@@ -557,46 +590,90 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
557
590
  }
558
591
 
559
592
  /*
560
- * call-seq:
561
- * Message.freeze => self
593
+ * ruby-doc: Map#frozen?
594
+ *
595
+ * Returns true if the map is frozen in either Ruby or the underlying
596
+ * representation. Freezes the Ruby map object if it is not already frozen in
597
+ * Ruby but it is frozen in the underlying representation.
562
598
  *
563
- * Freezes the message object. We have to intercept this so we can pin the
564
- * Ruby object into memory so we don't forget it's frozen.
599
+ * @return [Boolean]
565
600
  */
566
- static VALUE Map_freeze(VALUE _self) {
601
+ VALUE Map_frozen(VALUE _self) {
567
602
  Map* self = ruby_to_Map(_self);
568
- if (!RB_OBJ_FROZEN(_self)) {
569
- Arena_Pin(self->arena, _self);
570
- RB_OBJ_FREEZE(_self);
603
+ if (!upb_Map_IsFrozen(self->map)) {
604
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
605
+ return Qfalse;
571
606
  }
572
- return _self;
607
+
608
+ // Lazily freeze the Ruby wrapper.
609
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
610
+ return Qtrue;
573
611
  }
574
612
 
575
613
  /*
576
- * Deep freezes the map and values recursively.
577
- * Internal use only.
614
+ * ruby-doc: Map#freeze
615
+ *
616
+ * Freezes the map object. We have to intercept this so we can freeze the
617
+ * underlying representation, not just the Ruby wrapper.
618
+ *
619
+ * @return [self]
578
620
  */
579
- VALUE Map_internal_deep_freeze(VALUE _self) {
621
+ VALUE Map_freeze(VALUE _self) {
580
622
  Map* self = ruby_to_Map(_self);
581
- Map_freeze(_self);
582
- if (self->value_type_info.type == kUpb_CType_Message) {
583
- size_t iter = kUpb_Map_Begin;
584
- upb_MessageValue key, val;
623
+ if (RB_OBJ_FROZEN(_self)) {
624
+ PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
625
+ return _self;
626
+ }
585
627
 
586
- while (upb_Map_Next(self->map, &key, &val, &iter)) {
587
- VALUE val_val =
588
- Convert_UpbToRuby(val, self->value_type_info, self->arena);
589
- Message_internal_deep_freeze(val_val);
628
+ if (!upb_Map_IsFrozen(self->map)) {
629
+ if (self->value_type_info.type == kUpb_CType_Message) {
630
+ upb_Map_Freeze(
631
+ Map_GetMutable(_self),
632
+ upb_MessageDef_MiniTable(self->value_type_info.def.msgdef));
633
+ } else {
634
+ upb_Map_Freeze(Map_GetMutable(_self), NULL);
590
635
  }
591
636
  }
637
+
638
+ RB_OBJ_FREEZE(_self);
639
+
592
640
  return _self;
593
641
  }
594
642
 
643
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
644
+ PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
645
+ VALUE val = ObjectCache_Get(f);
646
+
647
+ if (val == Qnil) {
648
+ const upb_FieldDef* key_f = map_field_key(f);
649
+ const upb_FieldDef* val_f = map_field_value(f);
650
+ upb_CType key_type = upb_FieldDef_CType(key_f);
651
+ TypeInfo value_type_info = TypeInfo_get(val_f);
652
+ val = Map_alloc(cMap);
653
+ Map* self;
654
+ TypedData_Get_Struct(val, Map, &Map_type, self);
655
+ self->arena = Arena_new();
656
+ self->map =
657
+ upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type);
658
+ self->key_type = key_type;
659
+ self->value_type_info = value_type_info;
660
+ if (self->value_type_info.type == kUpb_CType_Message) {
661
+ const upb_MessageDef* val_m = value_type_info.def.msgdef;
662
+ self->value_type_class = Descriptor_DefToClass(val_m);
663
+ }
664
+ return ObjectCache_TryAdd(f, Map_freeze(val));
665
+ }
666
+ PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
667
+ PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
668
+ return val;
669
+ }
670
+
595
671
  /*
596
- * call-seq:
597
- * Map.hash => hash_value
672
+ * ruby-doc: Map#hash
598
673
  *
599
674
  * Returns a hash value based on this map's contents.
675
+ *
676
+ * @return [Integer]
600
677
  */
601
678
  VALUE Map_hash(VALUE _self) {
602
679
  Map* self = ruby_to_Map(_self);
@@ -606,18 +683,19 @@ VALUE Map_hash(VALUE _self) {
606
683
  TypeInfo key_info = {self->key_type};
607
684
  upb_MessageValue key, val;
608
685
  while (upb_Map_Next(self->map, &key, &val, &iter)) {
609
- hash = Msgval_GetHash(key, key_info, hash);
610
- hash = Msgval_GetHash(val, self->value_type_info, hash);
686
+ hash += Msgval_GetHash(key, key_info, 0);
687
+ hash += Msgval_GetHash(val, self->value_type_info, 0);
611
688
  }
612
689
 
613
690
  return LL2NUM(hash);
614
691
  }
615
692
 
616
693
  /*
617
- * call-seq:
618
- * Map.to_h => {}
694
+ * ruby-doc: Map#to_h
619
695
  *
620
696
  * Returns a Ruby Hash object containing all the values within the map
697
+ *
698
+ * @return [Hash]
621
699
  */
622
700
  VALUE Map_to_h(VALUE _self) {
623
701
  Map* self = ruby_to_Map(_self);
@@ -625,12 +703,13 @@ VALUE Map_to_h(VALUE _self) {
625
703
  }
626
704
 
627
705
  /*
628
- * call-seq:
629
- * Map.inspect => string
706
+ * ruby-doc: Map#inspect
630
707
  *
631
708
  * Returns a string representing this map's elements. It will be formatted as
632
709
  * "{key => value, key => value, ...}", with each key and value string
633
710
  * representation computed by its own #inspect method.
711
+ *
712
+ * @return [String]
634
713
  */
635
714
  VALUE Map_inspect(VALUE _self) {
636
715
  Map* self = ruby_to_Map(_self);
@@ -643,13 +722,15 @@ VALUE Map_inspect(VALUE _self) {
643
722
  }
644
723
 
645
724
  /*
646
- * call-seq:
647
- * Map.merge(other_map) => map
725
+ * ruby-doc: Map#merge
648
726
  *
649
727
  * Copies key/value pairs from other_map into a copy of this map. If a key is
650
728
  * set in other_map and this map, the value from other_map overwrites the value
651
729
  * in the new copy of this map. Returns the new copy of this map with merged
652
730
  * contents.
731
+ *
732
+ * @param other_map [Map]
733
+ * @return [Map]
653
734
  */
654
735
  static VALUE Map_merge(VALUE _self, VALUE hashmap) {
655
736
  VALUE dupped = Map_dup(_self);
@@ -678,6 +759,7 @@ void Map_register(VALUE module) {
678
759
  rb_define_method(klass, "clone", Map_dup, 0);
679
760
  rb_define_method(klass, "==", Map_eq, 1);
680
761
  rb_define_method(klass, "freeze", Map_freeze, 0);
762
+ rb_define_method(klass, "frozen?", Map_frozen, 0);
681
763
  rb_define_method(klass, "hash", Map_hash, 0);
682
764
  rb_define_method(klass, "to_h", Map_to_h, 0);
683
765
  rb_define_method(klass, "inspect", Map_inspect, 0);
@@ -11,10 +11,14 @@
11
11
  #include "protobuf.h"
12
12
  #include "ruby-upb.h"
13
13
 
14
+ // Returns a frozen sentinel Ruby wrapper object for an empty upb_Map with the
15
+ // key and value types specified by the field. Creates one if it doesn't exist.
16
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f);
17
+
14
18
  // Returns a Ruby wrapper object for the given map, which will be created if
15
19
  // one does not exist already.
16
- VALUE Map_GetRubyWrapper(upb_Map *map, upb_CType key_type, TypeInfo value_type,
17
- VALUE arena);
20
+ VALUE Map_GetRubyWrapper(const upb_Map *map, upb_CType key_type,
21
+ TypeInfo value_type, VALUE arena);
18
22
 
19
23
  // Gets the underlying upb_Map for this Ruby map object, which must have
20
24
  // key/value type that match |field|. If this is not a map or the type doesn't
@@ -39,6 +43,6 @@ extern VALUE cMap;
39
43
  void Map_register(VALUE module);
40
44
 
41
45
  // Recursively freeze map
42
- VALUE Map_internal_deep_freeze(VALUE _self);
46
+ VALUE Map_freeze(VALUE _self);
43
47
 
44
48
  #endif // RUBY_PROTOBUF_MAP_H_