google-protobuf 3.25.5 → 4.28.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.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +46 -18
  3. data/ext/google/protobuf_c/defs.c +368 -29
  4. data/ext/google/protobuf_c/extconf.rb +1 -1
  5. data/ext/google/protobuf_c/glue.c +16 -0
  6. data/ext/google/protobuf_c/map.c +74 -29
  7. data/ext/google/protobuf_c/map.h +7 -3
  8. data/ext/google/protobuf_c/message.c +106 -114
  9. data/ext/google/protobuf_c/message.h +2 -6
  10. data/ext/google/protobuf_c/protobuf.c +30 -15
  11. data/ext/google/protobuf_c/protobuf.h +3 -7
  12. data/ext/google/protobuf_c/repeated_field.c +58 -23
  13. data/ext/google/protobuf_c/repeated_field.h +6 -2
  14. data/ext/google/protobuf_c/ruby-upb.c +13047 -10836
  15. data/ext/google/protobuf_c/ruby-upb.h +11114 -9028
  16. data/ext/google/protobuf_c/shared_convert.c +10 -5
  17. data/ext/google/protobuf_c/shared_convert.h +2 -2
  18. data/ext/google/protobuf_c/shared_message.c +3 -31
  19. data/ext/google/protobuf_c/shared_message.h +0 -4
  20. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
  21. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
  22. data/lib/google/protobuf/any_pb.rb +1 -22
  23. data/lib/google/protobuf/api_pb.rb +1 -24
  24. data/lib/google/protobuf/descriptor_pb.rb +3 -23
  25. data/lib/google/protobuf/duration_pb.rb +1 -22
  26. data/lib/google/protobuf/empty_pb.rb +1 -22
  27. data/lib/google/protobuf/ffi/descriptor.rb +4 -4
  28. data/lib/google/protobuf/ffi/descriptor_pool.rb +3 -1
  29. data/lib/google/protobuf/ffi/enum_descriptor.rb +3 -1
  30. data/lib/google/protobuf/ffi/ffi.rb +3 -6
  31. data/lib/google/protobuf/ffi/field_descriptor.rb +13 -2
  32. data/lib/google/protobuf/ffi/file_descriptor.rb +3 -13
  33. data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
  34. data/lib/google/protobuf/ffi/internal/convert.rb +21 -30
  35. data/lib/google/protobuf/ffi/map.rb +50 -24
  36. data/lib/google/protobuf/ffi/message.rb +183 -64
  37. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  38. data/lib/google/protobuf/ffi/object_cache.rb +3 -3
  39. data/lib/google/protobuf/ffi/oneof_descriptor.rb +3 -1
  40. data/lib/google/protobuf/ffi/repeated_field.rb +47 -19
  41. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  42. data/lib/google/protobuf/field_mask_pb.rb +1 -22
  43. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  44. data/lib/google/protobuf/plugin_pb.rb +2 -24
  45. data/lib/google/protobuf/repeated_field.rb +4 -5
  46. data/lib/google/protobuf/source_context_pb.rb +1 -22
  47. data/lib/google/protobuf/struct_pb.rb +1 -22
  48. data/lib/google/protobuf/timestamp_pb.rb +1 -22
  49. data/lib/google/protobuf/type_pb.rb +1 -24
  50. data/lib/google/protobuf/wrappers_pb.rb +1 -22
  51. data/lib/google/protobuf.rb +1 -1
  52. data/lib/google/protobuf_ffi.rb +3 -2
  53. data/lib/google/protobuf_native.rb +0 -1
  54. data/lib/google/tasks/ffi.rake +1 -3
  55. metadata +25 -12
  56. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  57. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  58. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  59. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  60. data/lib/google/protobuf/object_cache.rb +0 -97
@@ -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,
@@ -212,7 +215,7 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
212
215
  Map* self = ruby_to_Map(_self);
213
216
  Map* other = ruby_to_Map(hashmap);
214
217
  upb_Arena* arena = Arena_get(self->arena);
215
- upb_Message* self_msg = Map_GetMutable(_self);
218
+ upb_Map* self_map = Map_GetMutable(_self);
216
219
 
217
220
  Arena_fuse(other->arena, arena);
218
221
 
@@ -225,7 +228,7 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
225
228
  size_t iter = kUpb_Map_Begin;
226
229
  upb_MessageValue key, val;
227
230
  while (upb_Map_Next(other->map, &key, &val, &iter)) {
228
- upb_Map_Set(self_msg, key, val, arena);
231
+ upb_Map_Set(self_map, key, val, arena);
229
232
  }
230
233
  } else {
231
234
  rb_raise(rb_eArgError, "Unknown type merging into Map");
@@ -437,14 +440,14 @@ static VALUE Map_has_key(VALUE _self, VALUE key) {
437
440
  * nil if none was present. Throws an exception if the key is of the wrong type.
438
441
  */
439
442
  static VALUE Map_delete(VALUE _self, VALUE key) {
443
+ upb_Map* map = Map_GetMutable(_self);
440
444
  Map* self = ruby_to_Map(_self);
441
- rb_check_frozen(_self);
442
445
 
443
446
  upb_MessageValue key_upb =
444
447
  Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
445
448
  upb_MessageValue val_upb;
446
449
 
447
- if (upb_Map_Delete(self->map, key_upb, &val_upb)) {
450
+ if (upb_Map_Delete(map, key_upb, &val_upb)) {
448
451
  return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
449
452
  } else {
450
453
  return Qnil;
@@ -558,40 +561,81 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
558
561
 
559
562
  /*
560
563
  * call-seq:
561
- * Message.freeze => self
564
+ * Map.frozen? => bool
562
565
  *
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.
566
+ * Returns true if the map is frozen in either Ruby or the underlying
567
+ * representation. Freezes the Ruby map object if it is not already frozen in
568
+ * Ruby but it is frozen in the underlying representation.
565
569
  */
566
- static VALUE Map_freeze(VALUE _self) {
570
+ VALUE Map_frozen(VALUE _self) {
567
571
  Map* self = ruby_to_Map(_self);
568
- if (!RB_OBJ_FROZEN(_self)) {
569
- Arena_Pin(self->arena, _self);
570
- RB_OBJ_FREEZE(_self);
572
+ if (!upb_Map_IsFrozen(self->map)) {
573
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
574
+ return Qfalse;
571
575
  }
572
- return _self;
576
+
577
+ // Lazily freeze the Ruby wrapper.
578
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
579
+ return Qtrue;
573
580
  }
574
581
 
575
582
  /*
576
- * Deep freezes the map and values recursively.
577
- * Internal use only.
583
+ * call-seq:
584
+ * Map.freeze => self
585
+ *
586
+ * Freezes the map object. We have to intercept this so we can freeze the
587
+ * underlying representation, not just the Ruby wrapper.
578
588
  */
579
- VALUE Map_internal_deep_freeze(VALUE _self) {
589
+ VALUE Map_freeze(VALUE _self) {
580
590
  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;
591
+ if (RB_OBJ_FROZEN(_self)) {
592
+ PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
593
+ return _self;
594
+ }
585
595
 
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);
596
+ if (!upb_Map_IsFrozen(self->map)) {
597
+ if (self->value_type_info.type == kUpb_CType_Message) {
598
+ upb_Map_Freeze(
599
+ Map_GetMutable(_self),
600
+ upb_MessageDef_MiniTable(self->value_type_info.def.msgdef));
601
+ } else {
602
+ upb_Map_Freeze(Map_GetMutable(_self), NULL);
590
603
  }
591
604
  }
605
+
606
+ RB_OBJ_FREEZE(_self);
607
+
592
608
  return _self;
593
609
  }
594
610
 
611
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
612
+ PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
613
+ VALUE val = ObjectCache_Get(f);
614
+
615
+ if (val == Qnil) {
616
+ const upb_FieldDef* key_f = map_field_key(f);
617
+ const upb_FieldDef* val_f = map_field_value(f);
618
+ upb_CType key_type = upb_FieldDef_CType(key_f);
619
+ TypeInfo value_type_info = TypeInfo_get(val_f);
620
+ val = Map_alloc(cMap);
621
+ Map* self;
622
+ TypedData_Get_Struct(val, Map, &Map_type, self);
623
+ self->arena = Arena_new();
624
+ self->map =
625
+ upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type);
626
+ self->key_type = key_type;
627
+ self->value_type_info = value_type_info;
628
+ if (self->value_type_info.type == kUpb_CType_Message) {
629
+ const upb_MessageDef* val_m = value_type_info.def.msgdef;
630
+ self->value_type_class = Descriptor_DefToClass(val_m);
631
+ }
632
+ return ObjectCache_TryAdd(f, Map_freeze(val));
633
+ }
634
+ PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
635
+ PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
636
+ return val;
637
+ }
638
+
595
639
  /*
596
640
  * call-seq:
597
641
  * Map.hash => hash_value
@@ -678,6 +722,7 @@ void Map_register(VALUE module) {
678
722
  rb_define_method(klass, "clone", Map_dup, 0);
679
723
  rb_define_method(klass, "==", Map_eq, 1);
680
724
  rb_define_method(klass, "freeze", Map_freeze, 0);
725
+ rb_define_method(klass, "frozen?", Map_frozen, 0);
681
726
  rb_define_method(klass, "hash", Map_hash, 0);
682
727
  rb_define_method(klass, "to_h", Map_to_h, 0);
683
728
  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_
@@ -44,9 +44,11 @@ static void Message_mark(void* _self) {
44
44
  rb_gc_mark(self->arena);
45
45
  }
46
46
 
47
+ static size_t Message_memsize(const void* _self) { return sizeof(Message); }
48
+
47
49
  static rb_data_type_t Message_type = {
48
50
  "Google::Protobuf::Message",
49
- {Message_mark, RUBY_DEFAULT_FREE, NULL},
51
+ {Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
50
52
  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
51
53
  };
52
54
 
@@ -78,11 +80,13 @@ const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
78
80
  }
79
81
 
80
82
  upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
81
- rb_check_frozen(msg_rb);
82
- return (upb_Message*)Message_Get(msg_rb, m);
83
+ const upb_Message* upb_msg = Message_Get(msg_rb, m);
84
+ Protobuf_CheckNotFrozen(msg_rb, upb_Message_IsFrozen(upb_msg));
85
+ return (upb_Message*)upb_msg;
83
86
  }
84
87
 
85
- void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
88
+ void Message_InitPtr(VALUE self_, const upb_Message* msg, VALUE arena) {
89
+ PBRUBY_ASSERT(arena != Qnil);
86
90
  Message* self = ruby_to_Message(self_);
87
91
  self->msg = msg;
88
92
  RB_OBJ_WRITE(self_, &self->arena, arena);
@@ -103,7 +107,7 @@ void Message_CheckClass(VALUE klass) {
103
107
  }
104
108
  }
105
109
 
106
- VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
110
+ VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
107
111
  VALUE arena) {
108
112
  if (msg == NULL) return Qnil;
109
113
 
@@ -114,7 +118,6 @@ VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
114
118
  val = Message_alloc(klass);
115
119
  Message_InitPtr(val, msg, arena);
116
120
  }
117
-
118
121
  return val;
119
122
  }
120
123
 
@@ -246,7 +249,7 @@ static int extract_method_call(VALUE method_name, Message* self,
246
249
  static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
247
250
  int accessor_type) {
248
251
  Message* self = ruby_to_Message(_self);
249
- const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
252
+ const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o);
250
253
 
251
254
  switch (accessor_type) {
252
255
  case METHOD_PRESENCE:
@@ -286,13 +289,42 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
286
289
  upb_Message_SetFieldByDef(msg, f, msgval, arena);
287
290
  }
288
291
 
292
+ VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f,
293
+ VALUE arena) {
294
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
295
+ if (upb_FieldDef_IsMap(f)) {
296
+ if (msgval.map_val == NULL) {
297
+ return Map_EmptyFrozen(f);
298
+ }
299
+ const upb_FieldDef* key_f = map_field_key(f);
300
+ const upb_FieldDef* val_f = map_field_value(f);
301
+ upb_CType key_type = upb_FieldDef_CType(key_f);
302
+ TypeInfo value_type_info = TypeInfo_get(val_f);
303
+ return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, arena);
304
+ }
305
+ if (upb_FieldDef_IsRepeated(f)) {
306
+ if (msgval.array_val == NULL) {
307
+ return RepeatedField_EmptyFrozen(f);
308
+ }
309
+ return RepeatedField_GetRubyWrapper(msgval.array_val, TypeInfo_get(f),
310
+ arena);
311
+ }
312
+ VALUE ret;
313
+ if (upb_FieldDef_IsSubMessage(f)) {
314
+ const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
315
+ ret = Message_GetRubyWrapper(msgval.msg_val, m, arena);
316
+ } else {
317
+ ret = Convert_UpbToRuby(msgval, TypeInfo_get(f), Qnil);
318
+ }
319
+ return ret;
320
+ }
321
+
289
322
  VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
290
323
  Message* self = ruby_to_Message(_self);
291
- // This is a special-case: upb_Message_Mutable() for map & array are logically
292
- // const (they will not change what is serialized) but physically
293
- // non-const, as they do allocate a repeated field or map. The logical
294
- // constness means it's ok to do even if the message is frozen.
295
- upb_Message* msg = (upb_Message*)self->msg;
324
+ if (upb_Message_IsFrozen(self->msg)) {
325
+ return Message_getfield_frozen(self->msg, f, self->arena);
326
+ }
327
+ upb_Message* msg = Message_GetMutable(_self, NULL);
296
328
  upb_Arena* arena = Arena_get(self->arena);
297
329
  if (upb_FieldDef_IsMap(f)) {
298
330
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
@@ -305,12 +337,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
305
337
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
306
338
  return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
307
339
  } else if (upb_FieldDef_IsSubMessage(f)) {
308
- if (!upb_Message_HasFieldByDef(self->msg, f)) return Qnil;
340
+ if (!upb_Message_HasFieldByDef(msg, f)) return Qnil;
309
341
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
310
342
  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
311
343
  return Message_GetRubyWrapper(submsg, m, self->arena);
312
344
  } else {
313
- upb_MessageValue msgval = upb_Message_GetFieldByDef(self->msg, f);
345
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
314
346
  return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
315
347
  }
316
348
  }
@@ -434,7 +466,6 @@ static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
434
466
  if (argc != 2) {
435
467
  rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
436
468
  }
437
- rb_check_frozen(_self);
438
469
  break;
439
470
  default:
440
471
  if (argc != 1) {
@@ -488,7 +519,8 @@ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
488
519
  k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
489
520
 
490
521
  if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
491
- upb_MiniTable* t = upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
522
+ const upb_MiniTable* t =
523
+ upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
492
524
  upb_Message* msg = upb_Message_New(t, map_init->arena);
493
525
  Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
494
526
  map_init->arena);
@@ -519,7 +551,7 @@ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
519
551
  upb_Arena* arena) {
520
552
  if (info.type == kUpb_CType_Message) {
521
553
  upb_MessageValue msgval;
522
- upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
554
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
523
555
  upb_Message* msg = upb_Message_New(t, arena);
524
556
  Message_InitFromValue(msg, info.def.msgdef, val, arena);
525
557
  msgval.msg_val = msg;
@@ -635,7 +667,7 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
635
667
  Message* self = ruby_to_Message(_self);
636
668
  VALUE arena_rb = Arena_new();
637
669
  upb_Arena* arena = Arena_get(arena_rb);
638
- upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
670
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
639
671
  upb_Message* msg = upb_Message_New(t, arena);
640
672
 
641
673
  Message_InitPtr(_self, msg, arena_rb);
@@ -660,28 +692,12 @@ static VALUE Message_dup(VALUE _self) {
660
692
  Message* self = ruby_to_Message(_self);
661
693
  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
662
694
  Message* new_msg_self = ruby_to_Message(new_msg);
663
- size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
664
-
665
- // TODO
666
- // TODO
667
- memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
695
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
696
+ upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
668
697
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
669
698
  return new_msg;
670
699
  }
671
700
 
672
- // Support function for Message_eq, and also used by other #eq functions.
673
- bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
674
- const upb_MessageDef* m) {
675
- upb_Status status;
676
- upb_Status_Clear(&status);
677
- bool return_value = shared_Message_Equal(m1, m2, m, &status);
678
- if (upb_Status_IsOk(&status)) {
679
- return return_value;
680
- } else {
681
- rb_raise(cParseError, upb_Status_ErrorMessage(&status));
682
- }
683
- }
684
-
685
701
  /*
686
702
  * call-seq:
687
703
  * Message.==(other) => boolean
@@ -698,7 +714,10 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
698
714
  Message* other = ruby_to_Message(_other);
699
715
  assert(self->msgdef == other->msgdef);
700
716
 
701
- return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
717
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
718
+ const int options = 0;
719
+ return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue
720
+ : Qfalse;
702
721
  }
703
722
 
704
723
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
@@ -709,7 +728,8 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
709
728
  if (upb_Status_IsOk(&status)) {
710
729
  return return_value;
711
730
  } else {
712
- rb_raise(cParseError, upb_Status_ErrorMessage(&status));
731
+ rb_raise(cParseError, "Message_Hash(): %s",
732
+ upb_Status_ErrorMessage(&status));
713
733
  }
714
734
  }
715
735
 
@@ -766,58 +786,34 @@ static VALUE Message_CreateHash(const upb_Message* msg,
766
786
  if (!msg) return Qnil;
767
787
 
768
788
  VALUE hash = rb_hash_new();
769
- int n = upb_MessageDef_FieldCount(m);
770
- bool is_proto2;
771
-
772
- // We currently have a few behaviors that are specific to proto2.
773
- // This is unfortunate, we should key behaviors off field attributes (like
774
- // whether a field has presence), not proto2 vs. proto3. We should see if we
775
- // can change this without breaking users.
776
- is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
777
-
778
- for (int i = 0; i < n; i++) {
779
- const upb_FieldDef* field = upb_MessageDef_Field(m, i);
780
- TypeInfo type_info = TypeInfo_get(field);
781
- upb_MessageValue msgval;
782
- VALUE msg_value;
783
- VALUE msg_key;
784
-
785
- if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
786
- !upb_FieldDef_IsRepeated(field) &&
787
- !upb_Message_HasFieldByDef(msg, field)) {
788
- // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
789
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
790
- rb_hash_aset(hash, msg_key, Qnil);
791
- continue;
792
- }
789
+ size_t iter = kUpb_Message_Begin;
790
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m));
791
+ const upb_FieldDef* field;
792
+ upb_MessageValue val;
793
793
 
794
- // Do not include fields that are not present (oneof or optional fields).
795
- if (is_proto2 && upb_FieldDef_HasPresence(field) &&
796
- !upb_Message_HasFieldByDef(msg, field)) {
794
+ while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) {
795
+ if (upb_FieldDef_IsExtension(field)) {
796
+ // TODO: allow extensions once we have decided what naming scheme the
797
+ // symbol should use. eg. :"[pkg.ext]"
797
798
  continue;
798
799
  }
799
800
 
800
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
801
- msgval = upb_Message_GetFieldByDef(msg, field);
802
-
803
- // Proto2 omits empty map/repeated filds also.
801
+ TypeInfo type_info = TypeInfo_get(field);
802
+ VALUE msg_value;
804
803
 
805
804
  if (upb_FieldDef_IsMap(field)) {
806
805
  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
807
806
  const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
808
807
  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
809
808
  upb_CType key_type = upb_FieldDef_CType(key_f);
810
- msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f));
809
+ msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f));
811
810
  } else if (upb_FieldDef_IsRepeated(field)) {
812
- if (is_proto2 &&
813
- (!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
814
- continue;
815
- }
816
- msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
811
+ msg_value = RepeatedField_CreateArray(val.array_val, type_info);
817
812
  } else {
818
- msg_value = Scalar_CreateHash(msgval, type_info);
813
+ msg_value = Scalar_CreateHash(val, type_info);
819
814
  }
820
815
 
816
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
821
817
  rb_hash_aset(hash, msg_key, msg_value);
822
818
  }
823
819
 
@@ -845,43 +841,42 @@ static VALUE Message_to_h(VALUE _self) {
845
841
 
846
842
  /*
847
843
  * call-seq:
848
- * Message.freeze => self
844
+ * Message.frozen? => bool
849
845
  *
850
- * Freezes the message object. We have to intercept this so we can pin the
851
- * Ruby object into memory so we don't forget it's frozen.
846
+ * Returns true if the message is frozen in either Ruby or the underlying
847
+ * representation. Freezes the Ruby message object if it is not already frozen
848
+ * in Ruby but it is frozen in the underlying representation.
852
849
  */
853
- static VALUE Message_freeze(VALUE _self) {
850
+ VALUE Message_frozen(VALUE _self) {
854
851
  Message* self = ruby_to_Message(_self);
855
- if (!RB_OBJ_FROZEN(_self)) {
856
- Arena_Pin(self->arena, _self);
857
- RB_OBJ_FREEZE(_self);
852
+ if (!upb_Message_IsFrozen(self->msg)) {
853
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
854
+ return Qfalse;
858
855
  }
859
- return _self;
856
+
857
+ // Lazily freeze the Ruby wrapper.
858
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
859
+ return Qtrue;
860
860
  }
861
861
 
862
862
  /*
863
- * Deep freezes the message object recursively.
864
- * Internal use only.
863
+ * call-seq:
864
+ * Message.freeze => self
865
+ *
866
+ * Freezes the message object. We have to intercept this so we can freeze the
867
+ * underlying representation, not just the Ruby wrapper.
865
868
  */
866
- VALUE Message_internal_deep_freeze(VALUE _self) {
869
+ VALUE Message_freeze(VALUE _self) {
867
870
  Message* self = ruby_to_Message(_self);
868
- Message_freeze(_self);
869
-
870
- int n = upb_MessageDef_FieldCount(self->msgdef);
871
- for (int i = 0; i < n; i++) {
872
- const upb_FieldDef* f = upb_MessageDef_Field(self->msgdef, i);
873
- VALUE field = Message_getfield(_self, f);
874
-
875
- if (field != Qnil) {
876
- if (upb_FieldDef_IsMap(f)) {
877
- Map_internal_deep_freeze(field);
878
- } else if (upb_FieldDef_IsRepeated(f)) {
879
- RepeatedField_internal_deep_freeze(field);
880
- } else if (upb_FieldDef_IsSubMessage(f)) {
881
- Message_internal_deep_freeze(field);
882
- }
883
- }
871
+ if (RB_OBJ_FROZEN(_self)) {
872
+ PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg));
873
+ return _self;
884
874
  }
875
+ if (!upb_Message_IsFrozen(self->msg)) {
876
+ upb_Message_Freeze(Message_GetMutable(_self, NULL),
877
+ upb_MessageDef_MiniTable(self->msgdef));
878
+ }
879
+ RB_OBJ_FREEZE(_self);
885
880
  return _self;
886
881
  }
887
882
 
@@ -987,7 +982,7 @@ VALUE Message_decode_bytes(int size, const char* bytes, int options,
987
982
  rb_raise(cParseError, "Error occurred during parsing");
988
983
  }
989
984
  if (freeze) {
990
- Message_internal_deep_freeze(msg_rb);
985
+ Message_freeze(msg_rb);
991
986
  }
992
987
  return msg_rb;
993
988
  }
@@ -1009,9 +1004,6 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1009
1004
  int options = 0;
1010
1005
  upb_Status status;
1011
1006
 
1012
- // TODO: use this message's pool instead.
1013
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1014
-
1015
1007
  if (argc < 1 || argc > 2) {
1016
1008
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1017
1009
  }
@@ -1045,8 +1037,9 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1045
1037
  }
1046
1038
 
1047
1039
  upb_Status_Clear(&status);
1040
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1048
1041
  if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
1049
- (upb_Message*)msg->msg, msg->msgdef, symtab, options,
1042
+ (upb_Message*)msg->msg, msg->msgdef, pool, options,
1050
1043
  Arena_get(msg->arena), &status)) {
1051
1044
  rb_raise(cParseError, "Error occurred during parsing: %s",
1052
1045
  upb_Status_ErrorMessage(&status));
@@ -1125,9 +1118,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1125
1118
  size_t size;
1126
1119
  upb_Status status;
1127
1120
 
1128
- // TODO: use this message's pool instead.
1129
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1130
-
1131
1121
  if (argc < 1 || argc > 2) {
1132
1122
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1133
1123
  }
@@ -1162,8 +1152,9 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1162
1152
  }
1163
1153
 
1164
1154
  upb_Status_Clear(&status);
1165
- size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
1166
- sizeof(buf), &status);
1155
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1156
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1157
+ &status);
1167
1158
 
1168
1159
  if (!upb_Status_IsOk(&status)) {
1169
1160
  rb_raise(cParseError, "Error occurred during encoding: %s",
@@ -1173,7 +1164,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1173
1164
  VALUE ret;
1174
1165
  if (size >= sizeof(buf)) {
1175
1166
  char* buf2 = malloc(size + 1);
1176
- upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
1167
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1177
1168
  &status);
1178
1169
  ret = rb_str_new(buf2, size);
1179
1170
  free(buf2);
@@ -1399,6 +1390,7 @@ static void Message_define_class(VALUE klass) {
1399
1390
  rb_define_method(klass, "==", Message_eq, 1);
1400
1391
  rb_define_method(klass, "eql?", Message_eq, 1);
1401
1392
  rb_define_method(klass, "freeze", Message_freeze, 0);
1393
+ rb_define_method(klass, "frozen?", Message_frozen, 0);
1402
1394
  rb_define_method(klass, "hash", Message_hash, 0);
1403
1395
  rb_define_method(klass, "to_h", Message_to_h, 0);
1404
1396
  rb_define_method(klass, "inspect", Message_inspect, 0);
@@ -36,7 +36,7 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
36
36
 
37
37
  // Gets or constructs a Ruby wrapper object for the given message. The wrapper
38
38
  // object will reference |arena| and ensure that it outlives this object.
39
- VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
39
+ VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
40
40
  VALUE arena);
41
41
 
42
42
  // Gets the given field from this message.
@@ -54,10 +54,6 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
54
54
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
55
55
  upb_Arena* arena);
56
56
 
57
- // Returns true if these two messages are equal.
58
- bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
59
- const upb_MessageDef* m);
60
-
61
57
  // Checks that this Ruby object is a message, and raises an exception if not.
62
58
  void Message_CheckClass(VALUE klass);
63
59
 
@@ -78,7 +74,7 @@ VALUE Message_decode_bytes(int size, const char* bytes, int options,
78
74
  VALUE klass, bool freeze);
79
75
 
80
76
  // Recursively freeze message
81
- VALUE Message_internal_deep_freeze(VALUE _self);
77
+ VALUE Message_freeze(VALUE _self);
82
78
 
83
79
  // Call at startup to register all types in this module.
84
80
  void Message_register(VALUE protobuf);