google-protobuf 4.27.2 → 4.35.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +32 -14
  3. data/ext/google/protobuf_c/defs.c +475 -133
  4. data/ext/google/protobuf_c/extconf.rb +20 -10
  5. data/ext/google/protobuf_c/glue.c +63 -0
  6. data/ext/google/protobuf_c/map.c +145 -56
  7. data/ext/google/protobuf_c/map.h +6 -2
  8. data/ext/google/protobuf_c/message.c +180 -97
  9. data/ext/google/protobuf_c/message.h +2 -2
  10. data/ext/google/protobuf_c/protobuf.c +14 -13
  11. data/ext/google/protobuf_c/protobuf.h +3 -15
  12. data/ext/google/protobuf_c/repeated_field.c +134 -53
  13. data/ext/google/protobuf_c/repeated_field.h +5 -1
  14. data/ext/google/protobuf_c/ruby-upb.c +14522 -12698
  15. data/ext/google/protobuf_c/ruby-upb.h +8273 -4619
  16. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +22 -282
  17. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +2 -1
  18. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
  19. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
  20. data/lib/google/protobuf/any_pb.rb +1 -1
  21. data/lib/google/protobuf/api_pb.rb +2 -2
  22. data/lib/google/protobuf/descriptor_pb.rb +6 -2
  23. data/lib/google/protobuf/duration_pb.rb +1 -1
  24. data/lib/google/protobuf/empty_pb.rb +1 -1
  25. data/lib/google/protobuf/ffi/descriptor.rb +11 -2
  26. data/lib/google/protobuf/ffi/descriptor_pool.rb +7 -1
  27. data/lib/google/protobuf/ffi/enum_descriptor.rb +10 -0
  28. data/lib/google/protobuf/ffi/ffi.rb +5 -2
  29. data/lib/google/protobuf/ffi/field_descriptor.rb +16 -0
  30. data/lib/google/protobuf/ffi/file_descriptor.rb +36 -0
  31. data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
  32. data/lib/google/protobuf/ffi/internal/convert.rb +9 -6
  33. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +2 -1
  34. data/lib/google/protobuf/ffi/map.rb +47 -23
  35. data/lib/google/protobuf/ffi/message.rb +188 -64
  36. data/lib/google/protobuf/ffi/method_descriptor.rb +11 -1
  37. data/lib/google/protobuf/ffi/oneof_descriptor.rb +10 -0
  38. data/lib/google/protobuf/ffi/repeated_field.rb +42 -16
  39. data/lib/google/protobuf/ffi/service_descriptor.rb +11 -1
  40. data/lib/google/protobuf/field_mask_pb.rb +1 -1
  41. data/lib/google/protobuf/message_exts.rb +4 -0
  42. data/lib/google/protobuf/plugin_pb.rb +1 -1
  43. data/lib/google/protobuf/source_context_pb.rb +1 -1
  44. data/lib/google/protobuf/struct_pb.rb +1 -1
  45. data/lib/google/protobuf/timestamp_pb.rb +1 -1
  46. data/lib/google/protobuf/type_pb.rb +1 -1
  47. data/lib/google/protobuf/wrappers_pb.rb +1 -1
  48. data/lib/google/protobuf_ffi.rb +3 -2
  49. data/lib/google/tasks/ffi.rake +1 -1
  50. metadata +29 -34
  51. data/ext/google/protobuf_c/wrap_memcpy.c +0 -29
@@ -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
- "utf8_range.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,6 +75,15 @@ 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);
@@ -55,6 +91,15 @@ char* FieldDescriptor_serialized_options(const upb_FieldDef* fielddef,
55
91
  return serialized;
56
92
  }
57
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
+
58
103
  char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef,
59
104
  size_t* size, upb_Arena* arena) {
60
105
  const google_protobuf_ServiceOptions* opts =
@@ -64,9 +109,27 @@ char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef,
64
109
  return serialized;
65
110
  }
66
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
+
67
121
  char* MethodDescriptor_serialized_options(const upb_MethodDef* methoddef,
68
122
  size_t* size, upb_Arena* arena) {
69
123
  const google_protobuf_MethodOptions* opts = upb_MethodDef_Options(methoddef);
70
124
  char* serialized = google_protobuf_MethodOptions_serialize(opts, arena, size);
71
125
  return serialized;
72
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
+ }
@@ -63,9 +63,10 @@ static VALUE Map_alloc(VALUE klass) {
63
63
  return TypedData_Wrap_Struct(klass, &Map_type, self);
64
64
  }
65
65
 
66
- VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
67
- VALUE arena) {
66
+ VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
67
+ TypeInfo value_type, VALUE arena) {
68
68
  PBRUBY_ASSERT(map);
69
+ PBRUBY_ASSERT(arena != Qnil);
69
70
 
70
71
  VALUE val = ObjectCache_Get(map);
71
72
 
@@ -83,7 +84,6 @@ VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
83
84
  }
84
85
  return ObjectCache_TryAdd(map, val);
85
86
  }
86
-
87
87
  return val;
88
88
  }
89
89
 
@@ -105,8 +105,9 @@ static TypeInfo Map_keyinfo(Map* self) {
105
105
  }
106
106
 
107
107
  static upb_Map* Map_GetMutable(VALUE _self) {
108
- rb_check_frozen(_self);
109
- 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;
110
111
  }
111
112
 
112
113
  VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
@@ -235,10 +236,15 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
235
236
  return _self;
236
237
  }
237
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
+
238
246
  /*
239
- * call-seq:
240
- * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
241
- * => new map
247
+ * ruby-doc: Map#initialize
242
248
  *
243
249
  * Allocates a new Map container. This constructor may be called with 2, 3, or 4
244
250
  * arguments. The first two arguments are always present and are symbols (taking
@@ -264,6 +270,13 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
264
270
  * shallow-copied into the new Map: the original map is unmodified, but
265
271
  * references to underlying objects will be shared if the value type is a
266
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 {}
267
280
  */
268
281
  static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
269
282
  Map* self = ruby_to_Map(_self);
@@ -310,12 +323,14 @@ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
310
323
  }
311
324
 
312
325
  /*
313
- * call-seq:
314
- * Map.each(&block)
326
+ * ruby-doc: Map#each
315
327
  *
316
328
  * Invokes &block on each |key, value| pair in the map, in unspecified order.
317
329
  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
318
330
  * sequence.
331
+ *
332
+ * @yield [Object, Object]
333
+ * @return [nil]
319
334
  */
320
335
  static VALUE Map_each(VALUE _self) {
321
336
  Map* self = ruby_to_Map(_self);
@@ -332,10 +347,11 @@ static VALUE Map_each(VALUE _self) {
332
347
  }
333
348
 
334
349
  /*
335
- * call-seq:
336
- * Map.keys => [list_of_keys]
350
+ * ruby-doc: Map#keys
337
351
  *
338
352
  * Returns the list of keys contained in the map, in unspecified order.
353
+ *
354
+ * @return [Array<Object>]
339
355
  */
340
356
  static VALUE Map_keys(VALUE _self) {
341
357
  Map* self = ruby_to_Map(_self);
@@ -352,10 +368,11 @@ static VALUE Map_keys(VALUE _self) {
352
368
  }
353
369
 
354
370
  /*
355
- * call-seq:
356
- * Map.values => [list_of_values]
371
+ * ruby-doc: Map#values
357
372
  *
358
373
  * Returns the list of values contained in the map, in unspecified order.
374
+ *
375
+ * @return [Array<Object>]
359
376
  */
360
377
  static VALUE Map_values(VALUE _self) {
361
378
  Map* self = ruby_to_Map(_self);
@@ -372,11 +389,13 @@ static VALUE Map_values(VALUE _self) {
372
389
  }
373
390
 
374
391
  /*
375
- * call-seq:
376
- * Map.[](key) => value
392
+ * ruby-doc: Map#[]
377
393
  *
378
394
  * Accesses the element at the given key. Throws an exception if the key type is
379
395
  * incorrect. Returns nil when the key is not present in the map.
396
+ *
397
+ * @param key [Object]
398
+ * @return [Object]
380
399
  */
381
400
  static VALUE Map_index(VALUE _self, VALUE key) {
382
401
  Map* self = ruby_to_Map(_self);
@@ -392,12 +411,15 @@ static VALUE Map_index(VALUE _self, VALUE key) {
392
411
  }
393
412
 
394
413
  /*
395
- * call-seq:
396
- * Map.[]=(key, value) => value
414
+ * ruby-doc: Map#[]=
397
415
  *
398
416
  * Inserts or overwrites the value at the given key with the given new value.
399
417
  * Throws an exception if the key type is incorrect. Returns the new value that
400
418
  * was just inserted.
419
+ *
420
+ * @param key [Object]
421
+ * @param value [Object]
422
+ * @return [Object]
401
423
  */
402
424
  static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
403
425
  Map* self = ruby_to_Map(_self);
@@ -413,11 +435,13 @@ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
413
435
  }
414
436
 
415
437
  /*
416
- * call-seq:
417
- * Map.has_key?(key) => bool
438
+ * ruby-doc: Map#has_key?
418
439
  *
419
440
  * Returns true if the given key is present in the map. Throws an exception if
420
441
  * the key has the wrong type.
442
+ *
443
+ * @param key [Object]
444
+ * @return [Boolean]
421
445
  */
422
446
  static VALUE Map_has_key(VALUE _self, VALUE key) {
423
447
  Map* self = ruby_to_Map(_self);
@@ -432,21 +456,23 @@ static VALUE Map_has_key(VALUE _self, VALUE key) {
432
456
  }
433
457
 
434
458
  /*
435
- * call-seq:
436
- * Map.delete(key) => old_value
459
+ * ruby-doc: Map#delete
437
460
  *
438
461
  * Deletes the value at the given key, if any, returning either the old value or
439
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]
440
466
  */
441
467
  static VALUE Map_delete(VALUE _self, VALUE key) {
468
+ upb_Map* map = Map_GetMutable(_self);
442
469
  Map* self = ruby_to_Map(_self);
443
- rb_check_frozen(_self);
444
470
 
445
471
  upb_MessageValue key_upb =
446
472
  Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
447
473
  upb_MessageValue val_upb;
448
474
 
449
- if (upb_Map_Delete(Map_GetMutable(_self), key_upb, &val_upb)) {
475
+ if (upb_Map_Delete(map, key_upb, &val_upb)) {
450
476
  return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
451
477
  } else {
452
478
  return Qnil;
@@ -454,10 +480,11 @@ static VALUE Map_delete(VALUE _self, VALUE key) {
454
480
  }
455
481
 
456
482
  /*
457
- * call-seq:
458
- * Map.clear
483
+ * ruby-doc: Map#clear
459
484
  *
460
485
  * Removes all entries from the map.
486
+ *
487
+ * @return [nil]
461
488
  */
462
489
  static VALUE Map_clear(VALUE _self) {
463
490
  upb_Map_Clear(Map_GetMutable(_self));
@@ -465,10 +492,11 @@ static VALUE Map_clear(VALUE _self) {
465
492
  }
466
493
 
467
494
  /*
468
- * call-seq:
469
- * Map.length
495
+ * ruby-doc: Map#length
470
496
  *
471
497
  * Returns the number of entries (key-value pairs) in the map.
498
+ *
499
+ * @return [Integer]
472
500
  */
473
501
  static VALUE Map_length(VALUE _self) {
474
502
  Map* self = ruby_to_Map(_self);
@@ -476,11 +504,12 @@ static VALUE Map_length(VALUE _self) {
476
504
  }
477
505
 
478
506
  /*
479
- * call-seq:
480
- * Map.dup => new_map
507
+ * ruby-doc: Map#dup
481
508
  *
482
509
  * Duplicates this map with a shallow copy. References to all non-primitive
483
510
  * element objects (e.g., submessages) are shared.
511
+ *
512
+ * @return [Map]
484
513
  */
485
514
  static VALUE Map_dup(VALUE _self) {
486
515
  Map* self = ruby_to_Map(_self);
@@ -501,8 +530,7 @@ static VALUE Map_dup(VALUE _self) {
501
530
  }
502
531
 
503
532
  /*
504
- * call-seq:
505
- * Map.==(other) => boolean
533
+ * ruby-doc: Map#==
506
534
  *
507
535
  * Compares this map to another. Maps are equal if they have identical key sets,
508
536
  * and for each key, the values in both maps compare equal. Elements are
@@ -512,6 +540,9 @@ static VALUE Map_dup(VALUE _self) {
512
540
  * Maps with dissimilar key types or value types/typeclasses are never equal,
513
541
  * even if value comparison (for example, between integers and floats) would
514
542
  * have otherwise indicated that every element has equal value.
543
+ *
544
+ * @param other [Map]
545
+ * @return [Boolean]
515
546
  */
516
547
  VALUE Map_eq(VALUE _self, VALUE _other) {
517
548
  Map* self = ruby_to_Map(_self);
@@ -559,37 +590,90 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
559
590
  }
560
591
 
561
592
  /*
562
- * call-seq:
563
- * 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.
564
598
  *
565
- * Freezes the message object. We have to intercept this so we can pin the
566
- * Ruby object into memory so we don't forget it's frozen.
599
+ * @return [Boolean]
600
+ */
601
+ VALUE Map_frozen(VALUE _self) {
602
+ Map* self = ruby_to_Map(_self);
603
+ if (!upb_Map_IsFrozen(self->map)) {
604
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
605
+ return Qfalse;
606
+ }
607
+
608
+ // Lazily freeze the Ruby wrapper.
609
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
610
+ return Qtrue;
611
+ }
612
+
613
+ /*
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]
567
620
  */
568
621
  VALUE Map_freeze(VALUE _self) {
569
622
  Map* self = ruby_to_Map(_self);
623
+ if (RB_OBJ_FROZEN(_self)) {
624
+ PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
625
+ return _self;
626
+ }
627
+
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);
635
+ }
636
+ }
570
637
 
571
- if (RB_OBJ_FROZEN(_self)) return _self;
572
- Arena_Pin(self->arena, _self);
573
638
  RB_OBJ_FREEZE(_self);
574
639
 
575
- if (self->value_type_info.type == kUpb_CType_Message) {
576
- size_t iter = kUpb_Map_Begin;
577
- upb_MessageValue key, val;
640
+ return _self;
641
+ }
642
+
643
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
644
+ PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
645
+ VALUE val = ObjectCache_Get(f);
578
646
 
579
- while (upb_Map_Next(self->map, &key, &val, &iter)) {
580
- VALUE val_val =
581
- Convert_UpbToRuby(val, self->value_type_info, self->arena);
582
- Message_freeze(val_val);
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);
583
663
  }
664
+ return ObjectCache_TryAdd(f, Map_freeze(val));
584
665
  }
585
- return _self;
666
+ PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
667
+ PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
668
+ return val;
586
669
  }
587
670
 
588
671
  /*
589
- * call-seq:
590
- * Map.hash => hash_value
672
+ * ruby-doc: Map#hash
591
673
  *
592
674
  * Returns a hash value based on this map's contents.
675
+ *
676
+ * @return [Integer]
593
677
  */
594
678
  VALUE Map_hash(VALUE _self) {
595
679
  Map* self = ruby_to_Map(_self);
@@ -599,18 +683,19 @@ VALUE Map_hash(VALUE _self) {
599
683
  TypeInfo key_info = {self->key_type};
600
684
  upb_MessageValue key, val;
601
685
  while (upb_Map_Next(self->map, &key, &val, &iter)) {
602
- hash = Msgval_GetHash(key, key_info, hash);
603
- 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);
604
688
  }
605
689
 
606
690
  return LL2NUM(hash);
607
691
  }
608
692
 
609
693
  /*
610
- * call-seq:
611
- * Map.to_h => {}
694
+ * ruby-doc: Map#to_h
612
695
  *
613
696
  * Returns a Ruby Hash object containing all the values within the map
697
+ *
698
+ * @return [Hash]
614
699
  */
615
700
  VALUE Map_to_h(VALUE _self) {
616
701
  Map* self = ruby_to_Map(_self);
@@ -618,12 +703,13 @@ VALUE Map_to_h(VALUE _self) {
618
703
  }
619
704
 
620
705
  /*
621
- * call-seq:
622
- * Map.inspect => string
706
+ * ruby-doc: Map#inspect
623
707
  *
624
708
  * Returns a string representing this map's elements. It will be formatted as
625
709
  * "{key => value, key => value, ...}", with each key and value string
626
710
  * representation computed by its own #inspect method.
711
+ *
712
+ * @return [String]
627
713
  */
628
714
  VALUE Map_inspect(VALUE _self) {
629
715
  Map* self = ruby_to_Map(_self);
@@ -636,13 +722,15 @@ VALUE Map_inspect(VALUE _self) {
636
722
  }
637
723
 
638
724
  /*
639
- * call-seq:
640
- * Map.merge(other_map) => map
725
+ * ruby-doc: Map#merge
641
726
  *
642
727
  * Copies key/value pairs from other_map into a copy of this map. If a key is
643
728
  * set in other_map and this map, the value from other_map overwrites the value
644
729
  * in the new copy of this map. Returns the new copy of this map with merged
645
730
  * contents.
731
+ *
732
+ * @param other_map [Map]
733
+ * @return [Map]
646
734
  */
647
735
  static VALUE Map_merge(VALUE _self, VALUE hashmap) {
648
736
  VALUE dupped = Map_dup(_self);
@@ -671,6 +759,7 @@ void Map_register(VALUE module) {
671
759
  rb_define_method(klass, "clone", Map_dup, 0);
672
760
  rb_define_method(klass, "==", Map_eq, 1);
673
761
  rb_define_method(klass, "freeze", Map_freeze, 0);
762
+ rb_define_method(klass, "frozen?", Map_frozen, 0);
674
763
  rb_define_method(klass, "hash", Map_hash, 0);
675
764
  rb_define_method(klass, "to_h", Map_to_h, 0);
676
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