google-protobuf 3.23.3 → 4.31.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +60 -86
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +702 -60
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +20 -3
  8. data/ext/google/protobuf_c/glue.c +135 -0
  9. data/ext/google/protobuf_c/map.c +91 -47
  10. data/ext/google/protobuf_c/map.h +12 -30
  11. data/ext/google/protobuf_c/message.c +158 -166
  12. data/ext/google/protobuf_c/message.h +11 -33
  13. data/ext/google/protobuf_c/protobuf.c +62 -187
  14. data/ext/google/protobuf_c/protobuf.h +21 -39
  15. data/ext/google/protobuf_c/repeated_field.c +72 -38
  16. data/ext/google/protobuf_c/repeated_field.h +11 -29
  17. data/ext/google/protobuf_c/ruby-upb.c +15568 -11237
  18. data/ext/google/protobuf_c/ruby-upb.h +10632 -6097
  19. data/ext/google/protobuf_c/shared_convert.c +69 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +37 -0
  22. data/ext/google/protobuf_c/shared_message.h +21 -0
  23. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +207 -0
  24. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
  25. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
  26. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
  27. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  28. data/lib/google/protobuf/any_pb.rb +2 -23
  29. data/lib/google/protobuf/api_pb.rb +2 -25
  30. data/lib/google/protobuf/descriptor_pb.rb +19 -24
  31. data/lib/google/protobuf/duration_pb.rb +2 -23
  32. data/lib/google/protobuf/empty_pb.rb +2 -23
  33. data/lib/google/protobuf/ffi/descriptor.rb +175 -0
  34. data/lib/google/protobuf/ffi/descriptor_pool.rb +79 -0
  35. data/lib/google/protobuf/ffi/enum_descriptor.rb +183 -0
  36. data/lib/google/protobuf/ffi/ffi.rb +214 -0
  37. data/lib/google/protobuf/ffi/field_descriptor.rb +346 -0
  38. data/lib/google/protobuf/ffi/file_descriptor.rb +85 -0
  39. data/lib/google/protobuf/ffi/internal/arena.rb +60 -0
  40. data/lib/google/protobuf/ffi/internal/convert.rb +292 -0
  41. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +36 -0
  42. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  43. data/lib/google/protobuf/ffi/map.rb +433 -0
  44. data/lib/google/protobuf/ffi/message.rb +783 -0
  45. data/lib/google/protobuf/ffi/method_descriptor.rb +124 -0
  46. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  47. data/lib/google/protobuf/ffi/oneof_descriptor.rb +107 -0
  48. data/lib/google/protobuf/ffi/repeated_field.rb +411 -0
  49. data/lib/google/protobuf/ffi/service_descriptor.rb +117 -0
  50. data/lib/google/protobuf/field_mask_pb.rb +2 -23
  51. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  52. data/lib/google/protobuf/message_exts.rb +7 -26
  53. data/lib/google/protobuf/plugin_pb.rb +3 -25
  54. data/lib/google/protobuf/repeated_field.rb +7 -31
  55. data/lib/google/protobuf/source_context_pb.rb +2 -23
  56. data/lib/google/protobuf/struct_pb.rb +2 -23
  57. data/lib/google/protobuf/timestamp_pb.rb +2 -23
  58. data/lib/google/protobuf/type_pb.rb +2 -25
  59. data/lib/google/protobuf/well_known_types.rb +5 -34
  60. data/lib/google/protobuf/wrappers_pb.rb +2 -23
  61. data/lib/google/protobuf.rb +27 -45
  62. data/lib/google/protobuf_ffi.rb +52 -0
  63. data/lib/google/protobuf_native.rb +19 -0
  64. data/lib/google/tasks/ffi.rake +100 -0
  65. metadata +99 -16
  66. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  67. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  68. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  69. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
@@ -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,6 +12,7 @@
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;
40
18
  static VALUE cAbstractMessage = Qnil;
@@ -66,9 +44,11 @@ static void Message_mark(void* _self) {
66
44
  rb_gc_mark(self->arena);
67
45
  }
68
46
 
47
+ static size_t Message_memsize(const void* _self) { return sizeof(Message); }
48
+
69
49
  static rb_data_type_t Message_type = {
70
50
  "Google::Protobuf::Message",
71
- {Message_mark, RUBY_DEFAULT_FREE, NULL},
51
+ {Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
72
52
  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
73
53
  };
74
54
 
@@ -100,15 +80,19 @@ const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
100
80
  }
101
81
 
102
82
  upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
103
- rb_check_frozen(msg_rb);
104
- 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;
105
86
  }
106
87
 
107
- 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);
108
90
  Message* self = ruby_to_Message(self_);
109
91
  self->msg = msg;
110
92
  RB_OBJ_WRITE(self_, &self->arena, arena);
111
- ObjectCache_Add(msg, self_);
93
+ VALUE stored = ObjectCache_TryAdd(msg, self_);
94
+ (void)stored;
95
+ PBRUBY_ASSERT(stored == self_);
112
96
  }
113
97
 
114
98
  VALUE Message_GetArena(VALUE msg_rb) {
@@ -123,7 +107,7 @@ void Message_CheckClass(VALUE klass) {
123
107
  }
124
108
  }
125
109
 
126
- VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
110
+ VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
127
111
  VALUE arena) {
128
112
  if (msg == NULL) return Qnil;
129
113
 
@@ -134,7 +118,6 @@ VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
134
118
  val = Message_alloc(klass);
135
119
  Message_InitPtr(val, msg, arena);
136
120
  }
137
-
138
121
  return val;
139
122
  }
140
123
 
@@ -266,7 +249,7 @@ static int extract_method_call(VALUE method_name, Message* self,
266
249
  static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
267
250
  int accessor_type) {
268
251
  Message* self = ruby_to_Message(_self);
269
- const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
252
+ const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o);
270
253
 
271
254
  switch (accessor_type) {
272
255
  case METHOD_PRESENCE:
@@ -306,13 +289,42 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
306
289
  upb_Message_SetFieldByDef(msg, f, msgval, arena);
307
290
  }
308
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
+
309
322
  VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
310
323
  Message* self = ruby_to_Message(_self);
311
- // This is a special-case: upb_Message_Mutable() for map & array are logically
312
- // const (they will not change what is serialized) but physically
313
- // non-const, as they do allocate a repeated field or map. The logical
314
- // constness means it's ok to do even if the message is frozen.
315
- 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);
316
328
  upb_Arena* arena = Arena_get(self->arena);
317
329
  if (upb_FieldDef_IsMap(f)) {
318
330
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
@@ -325,12 +337,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
325
337
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
326
338
  return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
327
339
  } else if (upb_FieldDef_IsSubMessage(f)) {
328
- if (!upb_Message_HasFieldByDef(self->msg, f)) return Qnil;
340
+ if (!upb_Message_HasFieldByDef(msg, f)) return Qnil;
329
341
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
330
342
  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
331
343
  return Message_GetRubyWrapper(submsg, m, self->arena);
332
344
  } else {
333
- upb_MessageValue msgval = upb_Message_GetFieldByDef(self->msg, f);
345
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
334
346
  return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
335
347
  }
336
348
  }
@@ -350,7 +362,8 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
350
362
  if (!upb_FieldDef_HasPresence(f)) {
351
363
  rb_raise(rb_eRuntimeError, "Field does not have presence.");
352
364
  }
353
- return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f);
365
+ return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f) ? Qtrue
366
+ : Qfalse;
354
367
  case METHOD_WRAPPER_GETTER: {
355
368
  Message* self = ruby_to_Message(_self);
356
369
  if (upb_Message_HasFieldByDef(self->msg, f)) {
@@ -385,7 +398,7 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
385
398
  upb_MessageValue msgval =
386
399
  upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
387
400
 
388
- if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
401
+ if (upb_FieldDef_IsRepeated(f)) {
389
402
  // Map repeated fields to a new type with ints
390
403
  VALUE arr = rb_ary_new();
391
404
  size_t i, n = upb_Array_Size(msgval.array_val);
@@ -454,7 +467,6 @@ static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
454
467
  if (argc != 2) {
455
468
  rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
456
469
  }
457
- rb_check_frozen(_self);
458
470
  break;
459
471
  default:
460
472
  if (argc != 1) {
@@ -508,7 +520,8 @@ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
508
520
  k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
509
521
 
510
522
  if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
511
- upb_MiniTable* t = upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
523
+ const upb_MiniTable* t =
524
+ upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
512
525
  upb_Message* msg = upb_Message_New(t, map_init->arena);
513
526
  Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
514
527
  map_init->arena);
@@ -539,7 +552,7 @@ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
539
552
  upb_Arena* arena) {
540
553
  if (info.type == kUpb_CType_Message) {
541
554
  upb_MessageValue msgval;
542
- upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
555
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
543
556
  upb_Message* msg = upb_Message_New(t, arena);
544
557
  Message_InitFromValue(msg, info.def.msgdef, val, arena);
545
558
  msgval.msg_val = msg;
@@ -579,7 +592,7 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
579
592
  if (upb_FieldDef_IsMap(f)) {
580
593
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
581
594
  Map_InitFromValue(map, f, val, arena);
582
- } else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
595
+ } else if (upb_FieldDef_IsRepeated(f)) {
583
596
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
584
597
  RepeatedField_InitFromValue(arr, f, val, arena);
585
598
  } else if (upb_FieldDef_IsSubMessage(f)) {
@@ -655,7 +668,7 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
655
668
  Message* self = ruby_to_Message(_self);
656
669
  VALUE arena_rb = Arena_new();
657
670
  upb_Arena* arena = Arena_get(arena_rb);
658
- upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
671
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
659
672
  upb_Message* msg = upb_Message_New(t, arena);
660
673
 
661
674
  Message_InitPtr(_self, msg, arena_rb);
@@ -680,44 +693,12 @@ static VALUE Message_dup(VALUE _self) {
680
693
  Message* self = ruby_to_Message(_self);
681
694
  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
682
695
  Message* new_msg_self = ruby_to_Message(new_msg);
683
- size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
684
-
685
- // TODO(copy unknown fields?)
686
- // TODO(use official upb msg copy function)
687
- memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
696
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
697
+ upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
688
698
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
689
699
  return new_msg;
690
700
  }
691
701
 
692
- // Support function for Message_eq, and also used by other #eq functions.
693
- bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
694
- const upb_MessageDef* m) {
695
- if (m1 == m2) return true;
696
-
697
- size_t size1, size2;
698
- int encode_opts =
699
- kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic;
700
- upb_Arena* arena_tmp = upb_Arena_New();
701
- const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
702
-
703
- // Compare deterministically serialized payloads with no unknown fields.
704
- char* data1;
705
- char* data2;
706
- upb_EncodeStatus status1 =
707
- upb_Encode(m1, layout, encode_opts, arena_tmp, &data1, &size1);
708
- upb_EncodeStatus status2 =
709
- upb_Encode(m2, layout, encode_opts, arena_tmp, &data2, &size2);
710
-
711
- if (status1 == kUpb_EncodeStatus_Ok && status2 == kUpb_EncodeStatus_Ok) {
712
- bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
713
- upb_Arena_Free(arena_tmp);
714
- return ret;
715
- } else {
716
- upb_Arena_Free(arena_tmp);
717
- rb_raise(cParseError, "Error comparing messages");
718
- }
719
- }
720
-
721
702
  /*
722
703
  * call-seq:
723
704
  * Message.==(other) => boolean
@@ -734,28 +715,22 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
734
715
  Message* other = ruby_to_Message(_other);
735
716
  assert(self->msgdef == other->msgdef);
736
717
 
737
- return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
718
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
719
+ const int options = 0;
720
+ return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue
721
+ : Qfalse;
738
722
  }
739
723
 
740
724
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
741
725
  uint64_t seed) {
742
- upb_Arena* arena = upb_Arena_New();
743
- char* data;
744
- size_t size;
745
-
746
- // Hash a deterministically serialized payloads with no unknown fields.
747
- upb_EncodeStatus status = upb_Encode(
748
- msg, upb_MessageDef_MiniTable(m),
749
- kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena,
750
- &data, &size);
751
-
752
- if (status == kUpb_EncodeStatus_Ok) {
753
- uint64_t ret = _upb_Hash(data, size, seed);
754
- upb_Arena_Free(arena);
755
- return ret;
726
+ upb_Status status;
727
+ upb_Status_Clear(&status);
728
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
729
+ if (upb_Status_IsOk(&status)) {
730
+ return return_value;
756
731
  } else {
757
- upb_Arena_Free(arena);
758
- rb_raise(cParseError, "Error calculating hash");
732
+ rb_raise(cParseError, "Message_Hash(): %s",
733
+ upb_Status_ErrorMessage(&status));
759
734
  }
760
735
  }
761
736
 
@@ -812,58 +787,34 @@ static VALUE Message_CreateHash(const upb_Message* msg,
812
787
  if (!msg) return Qnil;
813
788
 
814
789
  VALUE hash = rb_hash_new();
815
- int n = upb_MessageDef_FieldCount(m);
816
- bool is_proto2;
817
-
818
- // We currently have a few behaviors that are specific to proto2.
819
- // This is unfortunate, we should key behaviors off field attributes (like
820
- // whether a field has presence), not proto2 vs. proto3. We should see if we
821
- // can change this without breaking users.
822
- is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
823
-
824
- for (int i = 0; i < n; i++) {
825
- const upb_FieldDef* field = upb_MessageDef_Field(m, i);
826
- TypeInfo type_info = TypeInfo_get(field);
827
- upb_MessageValue msgval;
828
- VALUE msg_value;
829
- VALUE msg_key;
830
-
831
- if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
832
- !upb_FieldDef_IsRepeated(field) &&
833
- !upb_Message_HasFieldByDef(msg, field)) {
834
- // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
835
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
836
- rb_hash_aset(hash, msg_key, Qnil);
837
- continue;
838
- }
790
+ size_t iter = kUpb_Message_Begin;
791
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m));
792
+ const upb_FieldDef* field;
793
+ upb_MessageValue val;
839
794
 
840
- // Do not include fields that are not present (oneof or optional fields).
841
- if (is_proto2 && upb_FieldDef_HasPresence(field) &&
842
- !upb_Message_HasFieldByDef(msg, field)) {
795
+ while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) {
796
+ if (upb_FieldDef_IsExtension(field)) {
797
+ // TODO: allow extensions once we have decided what naming scheme the
798
+ // symbol should use. eg. :"[pkg.ext]"
843
799
  continue;
844
800
  }
845
801
 
846
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
847
- msgval = upb_Message_GetFieldByDef(msg, field);
848
-
849
- // Proto2 omits empty map/repeated filds also.
802
+ TypeInfo type_info = TypeInfo_get(field);
803
+ VALUE msg_value;
850
804
 
851
805
  if (upb_FieldDef_IsMap(field)) {
852
806
  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
853
807
  const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
854
808
  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
855
809
  upb_CType key_type = upb_FieldDef_CType(key_f);
856
- msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f));
810
+ msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f));
857
811
  } else if (upb_FieldDef_IsRepeated(field)) {
858
- if (is_proto2 &&
859
- (!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
860
- continue;
861
- }
862
- msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
812
+ msg_value = RepeatedField_CreateArray(val.array_val, type_info);
863
813
  } else {
864
- msg_value = Scalar_CreateHash(msgval, type_info);
814
+ msg_value = Scalar_CreateHash(val, type_info);
865
815
  }
866
816
 
817
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
867
818
  rb_hash_aset(hash, msg_key, msg_value);
868
819
  }
869
820
 
@@ -889,19 +840,44 @@ static VALUE Message_to_h(VALUE _self) {
889
840
  return Message_CreateHash(self->msg, self->msgdef);
890
841
  }
891
842
 
843
+ /*
844
+ * call-seq:
845
+ * Message.frozen? => bool
846
+ *
847
+ * Returns true if the message is frozen in either Ruby or the underlying
848
+ * representation. Freezes the Ruby message object if it is not already frozen
849
+ * in Ruby but it is frozen in the underlying representation.
850
+ */
851
+ VALUE Message_frozen(VALUE _self) {
852
+ Message* self = ruby_to_Message(_self);
853
+ if (!upb_Message_IsFrozen(self->msg)) {
854
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
855
+ return Qfalse;
856
+ }
857
+
858
+ // Lazily freeze the Ruby wrapper.
859
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
860
+ return Qtrue;
861
+ }
862
+
892
863
  /*
893
864
  * call-seq:
894
865
  * Message.freeze => self
895
866
  *
896
- * Freezes the message object. We have to intercept this so we can pin the
897
- * Ruby object into memory so we don't forget it's frozen.
867
+ * Freezes the message object. We have to intercept this so we can freeze the
868
+ * underlying representation, not just the Ruby wrapper.
898
869
  */
899
- static VALUE Message_freeze(VALUE _self) {
870
+ VALUE Message_freeze(VALUE _self) {
900
871
  Message* self = ruby_to_Message(_self);
901
- if (!RB_OBJ_FROZEN(_self)) {
902
- Arena_Pin(self->arena, _self);
903
- RB_OBJ_FREEZE(_self);
872
+ if (RB_OBJ_FROZEN(_self)) {
873
+ PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg));
874
+ return _self;
875
+ }
876
+ if (!upb_Message_IsFrozen(self->msg)) {
877
+ upb_Message_Freeze(Message_GetMutable(_self, NULL),
878
+ upb_MessageDef_MiniTable(self->msgdef));
904
879
  }
880
+ RB_OBJ_FREEZE(_self);
905
881
  return _self;
906
882
  }
907
883
 
@@ -957,7 +933,7 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
957
933
  * MessageClass.decode(data, options) => message
958
934
  *
959
935
  * Decodes the given data (as a string containing bytes in protocol buffers wire
960
- * format) under the interpretration given by this message class's definition
936
+ * format) under the interpretation given by this message class's definition
961
937
  * and returns a message object with the corresponding field values.
962
938
  * @param options [Hash] options for the decoder
963
939
  * recursion_limit: set to maximum decoding depth for message (default is 64)
@@ -988,18 +964,27 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
988
964
  rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
989
965
  }
990
966
 
967
+ return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options,
968
+ klass, /*freeze*/ false);
969
+ }
970
+
971
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
972
+ VALUE klass, bool freeze) {
991
973
  VALUE msg_rb = initialize_rb_class_with_no_args(klass);
992
974
  Message* msg = ruby_to_Message(msg_rb);
993
975
 
994
- upb_DecodeStatus status =
995
- upb_Decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
996
- upb_MessageDef_MiniTable(msg->msgdef), NULL, options,
997
- Arena_get(msg->arena));
998
-
976
+ const upb_FileDef* file = upb_MessageDef_File(msg->msgdef);
977
+ const upb_ExtensionRegistry* extreg =
978
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
979
+ upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
980
+ upb_MessageDef_MiniTable(msg->msgdef),
981
+ extreg, options, Arena_get(msg->arena));
999
982
  if (status != kUpb_DecodeStatus_Ok) {
1000
983
  rb_raise(cParseError, "Error occurred during parsing");
1001
984
  }
1002
-
985
+ if (freeze) {
986
+ Message_freeze(msg_rb);
987
+ }
1003
988
  return msg_rb;
1004
989
  }
1005
990
 
@@ -1020,9 +1005,6 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1020
1005
  int options = 0;
1021
1006
  upb_Status status;
1022
1007
 
1023
- // TODO(haberman): use this message's pool instead.
1024
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1025
-
1026
1008
  if (argc < 1 || argc > 2) {
1027
1009
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1028
1010
  }
@@ -1043,7 +1025,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1043
1025
  rb_raise(rb_eArgError, "Expected string for JSON data.");
1044
1026
  }
1045
1027
 
1046
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
1028
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1047
1029
  // convert, because string handlers pass data directly to message string
1048
1030
  // fields.
1049
1031
 
@@ -1056,11 +1038,19 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1056
1038
  }
1057
1039
 
1058
1040
  upb_Status_Clear(&status);
1059
- if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
1060
- (upb_Message*)msg->msg, msg->msgdef, symtab, options,
1061
- Arena_get(msg->arena), &status)) {
1062
- rb_raise(cParseError, "Error occurred during parsing: %s",
1063
- upb_Status_ErrorMessage(&status));
1041
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1042
+
1043
+ int result = upb_JsonDecodeDetectingNonconformance(
1044
+ RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
1045
+ msg->msgdef, pool, options, Arena_get(msg->arena), &status);
1046
+
1047
+ switch (result) {
1048
+ case kUpb_JsonDecodeResult_Ok:
1049
+ break;
1050
+ case kUpb_JsonDecodeResult_Error:
1051
+ rb_raise(cParseError, "Error occurred during parsing: %s",
1052
+ upb_Status_ErrorMessage(&status));
1053
+ break;
1064
1054
  }
1065
1055
 
1066
1056
  return msg_rb;
@@ -1136,9 +1126,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1136
1126
  size_t size;
1137
1127
  upb_Status status;
1138
1128
 
1139
- // TODO(haberman): use this message's pool instead.
1140
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1141
-
1142
1129
  if (argc < 1 || argc > 2) {
1143
1130
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1144
1131
  }
@@ -1173,8 +1160,9 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1173
1160
  }
1174
1161
 
1175
1162
  upb_Status_Clear(&status);
1176
- size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
1177
- sizeof(buf), &status);
1163
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1164
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1165
+ &status);
1178
1166
 
1179
1167
  if (!upb_Status_IsOk(&status)) {
1180
1168
  rb_raise(cParseError, "Error occurred during encoding: %s",
@@ -1184,7 +1172,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1184
1172
  VALUE ret;
1185
1173
  if (size >= sizeof(buf)) {
1186
1174
  char* buf2 = malloc(size + 1);
1187
- upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
1175
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1188
1176
  &status);
1189
1177
  ret = rb_str_new(buf2, size);
1190
1178
  free(buf2);
@@ -1317,9 +1305,12 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1317
1305
  upb_Message* new_msg = upb_Message_New(layout, arena);
1318
1306
  char* data;
1319
1307
 
1308
+ const upb_FileDef* file = upb_MessageDef_File(m);
1309
+ const upb_ExtensionRegistry* extreg =
1310
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1320
1311
  if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1321
1312
  kUpb_EncodeStatus_Ok ||
1322
- upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
1313
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1323
1314
  kUpb_DecodeStatus_Ok) {
1324
1315
  upb_Arena_Free(tmp_arena);
1325
1316
  rb_raise(cParseError, "Error occurred copying proto");
@@ -1407,6 +1398,7 @@ static void Message_define_class(VALUE klass) {
1407
1398
  rb_define_method(klass, "==", Message_eq, 1);
1408
1399
  rb_define_method(klass, "eql?", Message_eq, 1);
1409
1400
  rb_define_method(klass, "freeze", Message_freeze, 0);
1401
+ rb_define_method(klass, "frozen?", Message_frozen, 0);
1410
1402
  rb_define_method(klass, "hash", Message_hash, 0);
1411
1403
  rb_define_method(klass, "to_h", Message_to_h, 0);
1412
1404
  rb_define_method(klass, "inspect", Message_inspect, 0);
@@ -1,38 +1,13 @@
1
1
  // Protocol Buffers - Google's data interchange format
2
2
  // Copyright 2008 Google Inc. All rights reserved.
3
- // https://developers.google.com/protocol-buffers/
4
3
  //
5
- // Redistribution and use in source and binary forms, with or without
6
- // modification, are permitted provided that the following conditions are
7
- // met:
8
- //
9
- // * Redistributions of source code must retain the above copyright
10
- // notice, this list of conditions and the following disclaimer.
11
- // * Redistributions in binary form must reproduce the above
12
- // copyright notice, this list of conditions and the following disclaimer
13
- // in the documentation and/or other materials provided with the
14
- // distribution.
15
- // * Neither the name of Google Inc. nor the names of its
16
- // contributors may be used to endorse or promote products derived from
17
- // this software without specific prior written permission.
18
- //
19
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4
+ // Use of this source code is governed by a BSD-style
5
+ // license that can be found in the LICENSE file or at
6
+ // https://developers.google.com/open-source/licenses/bsd
30
7
 
31
8
  #ifndef RUBY_PROTOBUF_MESSAGE_H_
32
9
  #define RUBY_PROTOBUF_MESSAGE_H_
33
10
 
34
- #include <ruby/ruby.h>
35
-
36
11
  #include "protobuf.h"
37
12
  #include "ruby-upb.h"
38
13
 
@@ -61,7 +36,7 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
61
36
 
62
37
  // Gets or constructs a Ruby wrapper object for the given message. The wrapper
63
38
  // object will reference |arena| and ensure that it outlives this object.
64
- VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
39
+ VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
65
40
  VALUE arena);
66
41
 
67
42
  // Gets the given field from this message.
@@ -79,10 +54,6 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
79
54
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
80
55
  upb_Arena* arena);
81
56
 
82
- // Returns true if these two messages are equal.
83
- bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
84
- const upb_MessageDef* m);
85
-
86
57
  // Checks that this Ruby object is a message, and raises an exception if not.
87
58
  void Message_CheckClass(VALUE klass);
88
59
 
@@ -98,6 +69,13 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc);
98
69
  // module.
99
70
  VALUE MessageOrEnum_GetDescriptor(VALUE klass);
100
71
 
72
+ // Decodes a Message from a byte sequence.
73
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
74
+ VALUE klass, bool freeze);
75
+
76
+ // Recursively freeze message
77
+ VALUE Message_freeze(VALUE _self);
78
+
101
79
  // Call at startup to register all types in this module.
102
80
  void Message_register(VALUE protobuf);
103
81