google-protobuf 3.21.10 → 3.25.5

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 (68) 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 +178 -55
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +4 -4
  8. data/ext/google/protobuf_c/glue.c +56 -0
  9. data/ext/google/protobuf_c/map.c +54 -70
  10. data/ext/google/protobuf_c/map.h +6 -28
  11. data/ext/google/protobuf_c/message.c +178 -161
  12. data/ext/google/protobuf_c/message.h +10 -28
  13. data/ext/google/protobuf_c/protobuf.c +39 -176
  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 +12326 -9027
  18. data/ext/google/protobuf_c/ruby-upb.h +11950 -4518
  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/third_party/utf8_range/LICENSE +1 -0
  24. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -0
  25. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +1 -1
  26. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -0
  27. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +13 -1
  28. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  29. data/lib/google/protobuf/any_pb.rb +24 -5
  30. data/lib/google/protobuf/api_pb.rb +26 -23
  31. data/lib/google/protobuf/descriptor_dsl.rb +0 -0
  32. data/lib/google/protobuf/descriptor_pb.rb +43 -226
  33. data/lib/google/protobuf/duration_pb.rb +24 -5
  34. data/lib/google/protobuf/empty_pb.rb +24 -3
  35. data/lib/google/protobuf/ffi/descriptor.rb +165 -0
  36. data/lib/google/protobuf/ffi/descriptor_pool.rb +75 -0
  37. data/lib/google/protobuf/ffi/enum_descriptor.rb +171 -0
  38. data/lib/google/protobuf/ffi/ffi.rb +213 -0
  39. data/lib/google/protobuf/ffi/field_descriptor.rb +319 -0
  40. data/lib/google/protobuf/ffi/file_descriptor.rb +59 -0
  41. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  42. data/lib/google/protobuf/ffi/internal/convert.rb +305 -0
  43. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  44. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  45. data/lib/google/protobuf/ffi/map.rb +407 -0
  46. data/lib/google/protobuf/ffi/message.rb +662 -0
  47. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  48. data/lib/google/protobuf/ffi/oneof_descriptor.rb +95 -0
  49. data/lib/google/protobuf/ffi/repeated_field.rb +383 -0
  50. data/lib/google/protobuf/field_mask_pb.rb +24 -4
  51. data/lib/google/protobuf/message_exts.rb +8 -26
  52. data/lib/google/protobuf/object_cache.rb +97 -0
  53. data/lib/google/protobuf/plugin_pb.rb +47 -0
  54. data/lib/google/protobuf/repeated_field.rb +3 -26
  55. data/lib/google/protobuf/source_context_pb.rb +24 -4
  56. data/lib/google/protobuf/struct_pb.rb +24 -20
  57. data/lib/google/protobuf/timestamp_pb.rb +24 -5
  58. data/lib/google/protobuf/type_pb.rb +26 -68
  59. data/lib/google/protobuf/well_known_types.rb +5 -34
  60. data/lib/google/protobuf/wrappers_pb.rb +24 -28
  61. data/lib/google/protobuf.rb +27 -45
  62. data/lib/google/protobuf_ffi.rb +50 -0
  63. data/lib/google/protobuf_native.rb +20 -0
  64. data/lib/google/tasks/ffi.rake +102 -0
  65. metadata +75 -12
  66. data/tests/basic.rb +0 -739
  67. data/tests/generated_code_test.rb +0 -23
  68. data/tests/stress.rb +0 -38
@@ -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 "message.h"
32
9
 
@@ -35,8 +12,10 @@
35
12
  #include "map.h"
36
13
  #include "protobuf.h"
37
14
  #include "repeated_field.h"
15
+ #include "shared_message.h"
38
16
 
39
17
  static VALUE cParseError = Qnil;
18
+ static VALUE cAbstractMessage = Qnil;
40
19
  static ID descriptor_instancevar_interned;
41
20
 
42
21
  static VALUE initialize_rb_class_with_no_args(VALUE klass) {
@@ -52,6 +31,8 @@ VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
52
31
  // -----------------------------------------------------------------------------
53
32
 
54
33
  typedef struct {
34
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
35
+ // macro to update VALUE references, as to trigger write barriers.
55
36
  VALUE arena;
56
37
  const upb_Message* msg; // Can get as mutable when non-frozen.
57
38
  const upb_MessageDef*
@@ -64,9 +45,9 @@ static void Message_mark(void* _self) {
64
45
  }
65
46
 
66
47
  static rb_data_type_t Message_type = {
67
- "Message",
48
+ "Google::Protobuf::Message",
68
49
  {Message_mark, RUBY_DEFAULT_FREE, NULL},
69
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
50
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
70
51
  };
71
52
 
72
53
  static Message* ruby_to_Message(VALUE msg_rb) {
@@ -104,8 +85,10 @@ upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
104
85
  void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
105
86
  Message* self = ruby_to_Message(self_);
106
87
  self->msg = msg;
107
- self->arena = arena;
108
- ObjectCache_Add(msg, self_);
88
+ RB_OBJ_WRITE(self_, &self->arena, arena);
89
+ VALUE stored = ObjectCache_TryAdd(msg, self_);
90
+ (void)stored;
91
+ PBRUBY_ASSERT(stored == self_);
109
92
  }
110
93
 
111
94
  VALUE Message_GetArena(VALUE msg_rb) {
@@ -145,7 +128,8 @@ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
145
128
  for (int i = 0; i < n; i++) {
146
129
  const upb_FieldDef* field = upb_MessageDef_Field(m, i);
147
130
 
148
- if (upb_FieldDef_HasPresence(field) && !upb_Message_Has(msg, field)) {
131
+ if (upb_FieldDef_HasPresence(field) &&
132
+ !upb_Message_HasFieldByDef(msg, field)) {
149
133
  continue;
150
134
  }
151
135
 
@@ -155,7 +139,7 @@ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
155
139
  first = false;
156
140
  }
157
141
 
158
- upb_MessageValue msgval = upb_Message_Get(msg, field);
142
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field);
159
143
 
160
144
  StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field));
161
145
 
@@ -241,15 +225,6 @@ static int extract_method_call(VALUE method_name, Message* self,
241
225
  if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
242
226
  if (Match(m, name, f, o, "has_", "?") &&
243
227
  (*o || (*f && upb_FieldDef_HasPresence(*f)))) {
244
- // Disallow oneof hazzers for proto3.
245
- // TODO(haberman): remove this test when we are enabling oneof hazzers for
246
- // proto3.
247
- if (*f && !upb_FieldDef_IsSubMessage(*f) &&
248
- upb_FieldDef_RealContainingOneof(*f) &&
249
- upb_MessageDef_Syntax(upb_FieldDef_ContainingType(*f)) !=
250
- kUpb_Syntax_Proto2) {
251
- return METHOD_UNKNOWN;
252
- }
253
228
  return METHOD_PRESENCE;
254
229
  }
255
230
  if (Match(m, name, f, o, "", "_as_value") && *f &&
@@ -278,7 +253,8 @@ static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
278
253
  return oneof_field == NULL ? Qfalse : Qtrue;
279
254
  case METHOD_CLEAR:
280
255
  if (oneof_field != NULL) {
281
- upb_Message_ClearField(Message_GetMutable(_self, NULL), oneof_field);
256
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL),
257
+ oneof_field);
282
258
  }
283
259
  return Qnil;
284
260
  case METHOD_GETTER:
@@ -301,13 +277,13 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
301
277
  } else {
302
278
  if (val == Qnil &&
303
279
  (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) {
304
- upb_Message_ClearField(msg, f);
280
+ upb_Message_ClearFieldByDef(msg, f);
305
281
  return;
306
282
  }
307
283
  msgval =
308
284
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
309
285
  }
310
- upb_Message_Set(msg, f, msgval, arena);
286
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
311
287
  }
312
288
 
313
289
  VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
@@ -329,12 +305,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
329
305
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
330
306
  return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
331
307
  } else if (upb_FieldDef_IsSubMessage(f)) {
332
- if (!upb_Message_Has(self->msg, f)) return Qnil;
308
+ if (!upb_Message_HasFieldByDef(self->msg, f)) return Qnil;
333
309
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
334
310
  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
335
311
  return Message_GetRubyWrapper(submsg, m, self->arena);
336
312
  } else {
337
- upb_MessageValue msgval = upb_Message_Get(self->msg, f);
313
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(self->msg, f);
338
314
  return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
339
315
  }
340
316
  }
@@ -348,23 +324,24 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
348
324
  Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
349
325
  return Qnil;
350
326
  case METHOD_CLEAR:
351
- upb_Message_ClearField(Message_GetMutable(_self, NULL), f);
327
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f);
352
328
  return Qnil;
353
329
  case METHOD_PRESENCE:
354
330
  if (!upb_FieldDef_HasPresence(f)) {
355
331
  rb_raise(rb_eRuntimeError, "Field does not have presence.");
356
332
  }
357
- return upb_Message_Has(Message_Get(_self, NULL), f);
333
+ return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f);
358
334
  case METHOD_WRAPPER_GETTER: {
359
335
  Message* self = ruby_to_Message(_self);
360
- if (upb_Message_Has(self->msg, f)) {
336
+ if (upb_Message_HasFieldByDef(self->msg, f)) {
361
337
  PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
362
338
  !upb_FieldDef_IsRepeated(f));
363
- upb_MessageValue wrapper = upb_Message_Get(self->msg, f);
339
+ upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f);
364
340
  const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
365
341
  const upb_FieldDef* value_f =
366
342
  upb_MessageDef_FindFieldByNumber(wrapper_m, 1);
367
- upb_MessageValue value = upb_Message_Get(wrapper.msg_val, value_f);
343
+ upb_MessageValue value =
344
+ upb_Message_GetFieldByDef(wrapper.msg_val, value_f);
368
345
  return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
369
346
  } else {
370
347
  return Qnil;
@@ -373,19 +350,20 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
373
350
  case METHOD_WRAPPER_SETTER: {
374
351
  upb_Message* msg = Message_GetMutable(_self, NULL);
375
352
  if (argv[1] == Qnil) {
376
- upb_Message_ClearField(msg, f);
353
+ upb_Message_ClearFieldByDef(msg, f);
377
354
  } else {
378
355
  const upb_FieldDef* val_f =
379
356
  upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1);
380
357
  upb_MessageValue msgval = Convert_RubyToUpb(
381
358
  argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
382
359
  upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
383
- upb_Message_Set(wrapper, val_f, msgval, arena);
360
+ upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
384
361
  }
385
362
  return Qnil;
386
363
  }
387
364
  case METHOD_ENUM_GETTER: {
388
- upb_MessageValue msgval = upb_Message_Get(Message_Get(_self, NULL), f);
365
+ upb_MessageValue msgval =
366
+ upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
389
367
 
390
368
  if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
391
369
  // Map repeated fields to a new type with ints
@@ -510,8 +488,8 @@ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
510
488
  k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
511
489
 
512
490
  if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
513
- upb_Message* msg =
514
- upb_Message_New(map_init->val_type.def.msgdef, map_init->arena);
491
+ upb_MiniTable* t = upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
492
+ upb_Message* msg = upb_Message_New(t, map_init->arena);
515
493
  Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
516
494
  map_init->arena);
517
495
  v.msg_val = msg;
@@ -541,7 +519,8 @@ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
541
519
  upb_Arena* arena) {
542
520
  if (info.type == kUpb_CType_Message) {
543
521
  upb_MessageValue msgval;
544
- upb_Message* msg = upb_Message_New(info.def.msgdef, arena);
522
+ upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
523
+ upb_Message* msg = upb_Message_New(t, arena);
545
524
  Message_InitFromValue(msg, info.def.msgdef, val, arena);
546
525
  msgval.msg_val = msg;
547
526
  return msgval;
@@ -593,7 +572,7 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
593
572
  } else {
594
573
  upb_MessageValue msgval =
595
574
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
596
- upb_Message_Set(msg, f, msgval, arena);
575
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
597
576
  }
598
577
  }
599
578
 
@@ -656,7 +635,8 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
656
635
  Message* self = ruby_to_Message(_self);
657
636
  VALUE arena_rb = Arena_new();
658
637
  upb_Arena* arena = Arena_get(arena_rb);
659
- upb_Message* msg = upb_Message_New(self->msgdef, arena);
638
+ upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
639
+ upb_Message* msg = upb_Message_New(t, arena);
660
640
 
661
641
  Message_InitPtr(_self, msg, arena_rb);
662
642
 
@@ -682,8 +662,8 @@ static VALUE Message_dup(VALUE _self) {
682
662
  Message* new_msg_self = ruby_to_Message(new_msg);
683
663
  size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
684
664
 
685
- // TODO(copy unknown fields?)
686
- // TODO(use official upb msg copy function)
665
+ // TODO
666
+ // TODO
687
667
  memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
688
668
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
689
669
  return new_msg;
@@ -692,24 +672,13 @@ static VALUE Message_dup(VALUE _self) {
692
672
  // Support function for Message_eq, and also used by other #eq functions.
693
673
  bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
694
674
  const upb_MessageDef* m) {
695
- if (m1 == m2) return true;
696
-
697
- size_t size1, size2;
698
- int encode_opts = kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic;
699
- upb_Arena* arena_tmp = upb_Arena_New();
700
- const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
701
-
702
- // Compare deterministically serialized payloads with no unknown fields.
703
- char* data1 = upb_Encode(m1, layout, encode_opts, arena_tmp, &size1);
704
- char* data2 = upb_Encode(m2, layout, encode_opts, arena_tmp, &size2);
705
-
706
- if (data1 && data2) {
707
- bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
708
- upb_Arena_Free(arena_tmp);
709
- return ret;
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;
710
680
  } else {
711
- upb_Arena_Free(arena_tmp);
712
- rb_raise(cParseError, "Error comparing messages");
681
+ rb_raise(cParseError, upb_Status_ErrorMessage(&status));
713
682
  }
714
683
  }
715
684
 
@@ -734,22 +703,13 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
734
703
 
735
704
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
736
705
  uint64_t seed) {
737
- upb_Arena* arena = upb_Arena_New();
738
- const char* data;
739
- size_t size;
740
-
741
- // Hash a deterministically serialized payloads with no unknown fields.
742
- data = upb_Encode(msg, upb_MessageDef_MiniTable(m),
743
- kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic, arena,
744
- &size);
745
-
746
- if (data) {
747
- uint64_t ret = _upb_Hash(data, size, seed);
748
- upb_Arena_Free(arena);
749
- return ret;
706
+ upb_Status status;
707
+ upb_Status_Clear(&status);
708
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
709
+ if (upb_Status_IsOk(&status)) {
710
+ return return_value;
750
711
  } else {
751
- upb_Arena_Free(arena);
752
- rb_raise(cParseError, "Error calculating hash");
712
+ rb_raise(cParseError, upb_Status_ErrorMessage(&status));
753
713
  }
754
714
  }
755
715
 
@@ -823,7 +783,8 @@ static VALUE Message_CreateHash(const upb_Message* msg,
823
783
  VALUE msg_key;
824
784
 
825
785
  if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
826
- !upb_FieldDef_IsRepeated(field) && !upb_Message_Has(msg, field)) {
786
+ !upb_FieldDef_IsRepeated(field) &&
787
+ !upb_Message_HasFieldByDef(msg, field)) {
827
788
  // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
828
789
  msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
829
790
  rb_hash_aset(hash, msg_key, Qnil);
@@ -832,12 +793,12 @@ static VALUE Message_CreateHash(const upb_Message* msg,
832
793
 
833
794
  // Do not include fields that are not present (oneof or optional fields).
834
795
  if (is_proto2 && upb_FieldDef_HasPresence(field) &&
835
- !upb_Message_Has(msg, field)) {
796
+ !upb_Message_HasFieldByDef(msg, field)) {
836
797
  continue;
837
798
  }
838
799
 
839
800
  msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
840
- msgval = upb_Message_Get(msg, field);
801
+ msgval = upb_Message_GetFieldByDef(msg, field);
841
802
 
842
803
  // Proto2 omits empty map/repeated filds also.
843
804
 
@@ -898,6 +859,32 @@ static VALUE Message_freeze(VALUE _self) {
898
859
  return _self;
899
860
  }
900
861
 
862
+ /*
863
+ * Deep freezes the message object recursively.
864
+ * Internal use only.
865
+ */
866
+ VALUE Message_internal_deep_freeze(VALUE _self) {
867
+ 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
+ }
884
+ }
885
+ return _self;
886
+ }
887
+
901
888
  /*
902
889
  * call-seq:
903
890
  * Message.[](index) => value
@@ -940,7 +927,7 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
940
927
  }
941
928
 
942
929
  val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
943
- upb_Message_Set(Message_GetMutable(_self, NULL), f, val, arena);
930
+ upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
944
931
 
945
932
  return Qnil;
946
933
  }
@@ -950,7 +937,7 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
950
937
  * MessageClass.decode(data, options) => message
951
938
  *
952
939
  * Decodes the given data (as a string containing bytes in protocol buffers wire
953
- * format) under the interpretration given by this message class's definition
940
+ * format) under the interpretation given by this message class's definition
954
941
  * and returns a message object with the corresponding field values.
955
942
  * @param options [Hash] options for the decoder
956
943
  * recursion_limit: set to maximum decoding depth for message (default is 64)
@@ -969,10 +956,11 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
969
956
  rb_raise(rb_eArgError, "Expected hash arguments.");
970
957
  }
971
958
 
972
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
959
+ VALUE depth =
960
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
973
961
 
974
962
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
975
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
963
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
976
964
  }
977
965
  }
978
966
 
@@ -980,17 +968,27 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
980
968
  rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
981
969
  }
982
970
 
971
+ return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options,
972
+ klass, /*freeze*/ false);
973
+ }
974
+
975
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
976
+ VALUE klass, bool freeze) {
983
977
  VALUE msg_rb = initialize_rb_class_with_no_args(klass);
984
978
  Message* msg = ruby_to_Message(msg_rb);
985
979
 
986
- upb_DecodeStatus status = upb_Decode(
987
- RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
988
- upb_MessageDef_MiniTable(msg->msgdef), NULL, options, Arena_get(msg->arena));
989
-
980
+ const upb_FileDef* file = upb_MessageDef_File(msg->msgdef);
981
+ const upb_ExtensionRegistry* extreg =
982
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
983
+ upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
984
+ upb_MessageDef_MiniTable(msg->msgdef),
985
+ extreg, options, Arena_get(msg->arena));
990
986
  if (status != kUpb_DecodeStatus_Ok) {
991
987
  rb_raise(cParseError, "Error occurred during parsing");
992
988
  }
993
-
989
+ if (freeze) {
990
+ Message_internal_deep_freeze(msg_rb);
991
+ }
994
992
  return msg_rb;
995
993
  }
996
994
 
@@ -1011,7 +1009,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1011
1009
  int options = 0;
1012
1010
  upb_Status status;
1013
1011
 
1014
- // TODO(haberman): use this message's pool instead.
1012
+ // TODO: use this message's pool instead.
1015
1013
  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1016
1014
 
1017
1015
  if (argc < 1 || argc > 2) {
@@ -1034,7 +1032,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1034
1032
  rb_raise(rb_eArgError, "Expected string for JSON data.");
1035
1033
  }
1036
1034
 
1037
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
1035
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1038
1036
  // convert, because string handlers pass data directly to message string
1039
1037
  // fields.
1040
1038
 
@@ -1069,7 +1067,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1069
1067
  static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1070
1068
  Message* msg = ruby_to_Message(argv[0]);
1071
1069
  int options = 0;
1072
- const char* data;
1070
+ char* data;
1073
1071
  size_t size;
1074
1072
 
1075
1073
  if (CLASS_OF(argv[0]) != klass) {
@@ -1085,19 +1083,21 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1085
1083
  if (TYPE(hash_args) != T_HASH) {
1086
1084
  rb_raise(rb_eArgError, "Expected hash arguments.");
1087
1085
  }
1088
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1086
+ VALUE depth =
1087
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1089
1088
 
1090
1089
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1091
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
1090
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1092
1091
  }
1093
1092
  }
1094
1093
 
1095
- upb_Arena *arena = upb_Arena_New();
1094
+ upb_Arena* arena = upb_Arena_New();
1096
1095
 
1097
- data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef),
1098
- options, arena, &size);
1096
+ upb_EncodeStatus status =
1097
+ upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
1098
+ arena, &data, &size);
1099
1099
 
1100
- if (data) {
1100
+ if (status == kUpb_EncodeStatus_Ok) {
1101
1101
  VALUE ret = rb_str_new(data, size);
1102
1102
  rb_enc_associate(ret, rb_ascii8bit_encoding());
1103
1103
  upb_Arena_Free(arena);
@@ -1125,7 +1125,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1125
1125
  size_t size;
1126
1126
  upb_Status status;
1127
1127
 
1128
- // TODO(haberman): use this message's pool instead.
1128
+ // TODO: use this message's pool instead.
1129
1129
  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1130
1130
 
1131
1131
  if (argc < 1 || argc > 2) {
@@ -1135,7 +1135,8 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1135
1135
  if (argc == 2) {
1136
1136
  VALUE hash_args = argv[1];
1137
1137
  if (TYPE(hash_args) != T_HASH) {
1138
- if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, rb_str_new2("to_h")))) {
1138
+ if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1,
1139
+ rb_str_new2("to_h")))) {
1139
1140
  hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0);
1140
1141
  } else {
1141
1142
  rb_raise(rb_eArgError, "Expected hash arguments.");
@@ -1152,6 +1153,12 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1152
1153
  Qfalse))) {
1153
1154
  options |= upb_JsonEncode_EmitDefaults;
1154
1155
  }
1156
+
1157
+ if (RTEST(rb_hash_lookup2(hash_args,
1158
+ ID2SYM(rb_intern("format_enums_as_integers")),
1159
+ Qfalse))) {
1160
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
1161
+ }
1155
1162
  }
1156
1163
 
1157
1164
  upb_Status_Clear(&status);
@@ -1201,36 +1208,8 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
1201
1208
  klass = rb_define_class_id(
1202
1209
  // Docs say this parameter is ignored. User will assign return value to
1203
1210
  // their own toplevel constant class name.
1204
- rb_intern("Message"), rb_cObject);
1211
+ rb_intern("Message"), cAbstractMessage);
1205
1212
  rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
1206
- rb_define_alloc_func(klass, Message_alloc);
1207
- rb_require("google/protobuf/message_exts");
1208
- rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
1209
- rb_extend_object(
1210
- klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
1211
-
1212
- rb_define_method(klass, "method_missing", Message_method_missing, -1);
1213
- rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1214
- -1);
1215
- rb_define_method(klass, "initialize", Message_initialize, -1);
1216
- rb_define_method(klass, "dup", Message_dup, 0);
1217
- // Also define #clone so that we don't inherit Object#clone.
1218
- rb_define_method(klass, "clone", Message_dup, 0);
1219
- rb_define_method(klass, "==", Message_eq, 1);
1220
- rb_define_method(klass, "eql?", Message_eq, 1);
1221
- rb_define_method(klass, "freeze", Message_freeze, 0);
1222
- rb_define_method(klass, "hash", Message_hash, 0);
1223
- rb_define_method(klass, "to_h", Message_to_h, 0);
1224
- rb_define_method(klass, "inspect", Message_inspect, 0);
1225
- rb_define_method(klass, "to_s", Message_inspect, 0);
1226
- rb_define_method(klass, "[]", Message_index, 1);
1227
- rb_define_method(klass, "[]=", Message_index_set, 2);
1228
- rb_define_singleton_method(klass, "decode", Message_decode, -1);
1229
- rb_define_singleton_method(klass, "encode", Message_encode, -1);
1230
- rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1231
- rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1232
- rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1233
-
1234
1213
  return klass;
1235
1214
  }
1236
1215
 
@@ -1296,12 +1275,12 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1296
1275
  int32_t value = upb_EnumValueDef_Number(ev);
1297
1276
  if (name[0] < 'A' || name[0] > 'Z') {
1298
1277
  if (name[0] >= 'a' && name[0] <= 'z') {
1299
- name[0] -= 32; // auto capitalize
1278
+ name[0] -= 32; // auto capitalize
1300
1279
  } else {
1301
1280
  rb_warn(
1302
- "Enum value '%s' does not start with an uppercase letter "
1303
- "as is required for Ruby constants.",
1304
- name);
1281
+ "Enum value '%s' does not start with an uppercase letter "
1282
+ "as is required for Ruby constants.",
1283
+ name);
1305
1284
  }
1306
1285
  }
1307
1286
  rb_define_const(mod, name, INT2NUM(value));
@@ -1316,7 +1295,7 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1316
1295
  return mod;
1317
1296
  }
1318
1297
 
1319
- // Internal only; used by Google::Protobuf.deep_copy.
1298
+ // Internal to the library; used by Google::Protobuf.deep_copy.
1320
1299
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1321
1300
  upb_Arena* arena) {
1322
1301
  // Serialize and parse.
@@ -1324,11 +1303,16 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1324
1303
  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1325
1304
  size_t size;
1326
1305
 
1327
- char* data = upb_Encode(msg, layout, 0, tmp_arena, &size);
1328
- upb_Message* new_msg = upb_Message_New(m, arena);
1306
+ upb_Message* new_msg = upb_Message_New(layout, arena);
1307
+ char* data;
1329
1308
 
1330
- if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
1331
- kUpb_DecodeStatus_Ok) {
1309
+ const upb_FileDef* file = upb_MessageDef_File(m);
1310
+ const upb_ExtensionRegistry* extreg =
1311
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1312
+ if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1313
+ kUpb_EncodeStatus_Ok ||
1314
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1315
+ kUpb_DecodeStatus_Ok) {
1332
1316
  upb_Arena_Free(tmp_arena);
1333
1317
  rb_raise(cParseError, "Error occurred copying proto");
1334
1318
  }
@@ -1355,7 +1339,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1355
1339
  switch (upb_MessageDef_WellKnownType(m)) {
1356
1340
  case kUpb_WellKnown_Timestamp: {
1357
1341
  // Time -> Google::Protobuf::Timestamp
1358
- upb_Message* msg = upb_Message_New(m, arena);
1342
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1343
+ upb_Message* msg = upb_Message_New(t, arena);
1359
1344
  upb_MessageValue sec, nsec;
1360
1345
  struct timespec time;
1361
1346
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
@@ -1366,13 +1351,14 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1366
1351
  time = rb_time_timespec(value);
1367
1352
  sec.int64_val = time.tv_sec;
1368
1353
  nsec.int32_val = time.tv_nsec;
1369
- upb_Message_Set(msg, sec_f, sec, arena);
1370
- upb_Message_Set(msg, nsec_f, nsec, arena);
1354
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1355
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1371
1356
  return msg;
1372
1357
  }
1373
1358
  case kUpb_WellKnown_Duration: {
1374
1359
  // Numeric -> Google::Protobuf::Duration
1375
- upb_Message* msg = upb_Message_New(m, arena);
1360
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1361
+ upb_Message* msg = upb_Message_New(t, arena);
1376
1362
  upb_MessageValue sec, nsec;
1377
1363
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1378
1364
  const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
@@ -1381,8 +1367,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1381
1367
 
1382
1368
  sec.int64_val = NUM2LL(value);
1383
1369
  nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
1384
- upb_Message_Set(msg, sec_f, sec, arena);
1385
- upb_Message_Set(msg, nsec_f, nsec, arena);
1370
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1371
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1386
1372
  return msg;
1387
1373
  }
1388
1374
  default:
@@ -1399,11 +1385,42 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1399
1385
  return self->msg;
1400
1386
  }
1401
1387
 
1388
+ static void Message_define_class(VALUE klass) {
1389
+ rb_define_alloc_func(klass, Message_alloc);
1390
+
1391
+ rb_require("google/protobuf/message_exts");
1392
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
1393
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1394
+ -1);
1395
+ rb_define_method(klass, "initialize", Message_initialize, -1);
1396
+ rb_define_method(klass, "dup", Message_dup, 0);
1397
+ // Also define #clone so that we don't inherit Object#clone.
1398
+ rb_define_method(klass, "clone", Message_dup, 0);
1399
+ rb_define_method(klass, "==", Message_eq, 1);
1400
+ rb_define_method(klass, "eql?", Message_eq, 1);
1401
+ rb_define_method(klass, "freeze", Message_freeze, 0);
1402
+ rb_define_method(klass, "hash", Message_hash, 0);
1403
+ rb_define_method(klass, "to_h", Message_to_h, 0);
1404
+ rb_define_method(klass, "inspect", Message_inspect, 0);
1405
+ rb_define_method(klass, "to_s", Message_inspect, 0);
1406
+ rb_define_method(klass, "[]", Message_index, 1);
1407
+ rb_define_method(klass, "[]=", Message_index_set, 2);
1408
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
1409
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
1410
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1411
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1412
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1413
+ }
1414
+
1402
1415
  void Message_register(VALUE protobuf) {
1403
1416
  cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
1417
+ cAbstractMessage =
1418
+ rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
1419
+ Message_define_class(cAbstractMessage);
1420
+ rb_gc_register_address(&cAbstractMessage);
1404
1421
 
1405
1422
  // Ruby-interned string: "descriptor". We use this identifier to store an
1406
1423
  // instance variable on message classes we create in order to link them back
1407
1424
  // to their descriptors.
1408
- descriptor_instancevar_interned = rb_intern("descriptor");
1425
+ descriptor_instancevar_interned = rb_intern("@descriptor");
1409
1426
  }