google-protobuf 3.21.2 → 4.29.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +67 -86
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +538 -77
  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 +72 -0
  9. data/ext/google/protobuf_c/map.c +114 -85
  10. data/ext/google/protobuf_c/map.h +12 -30
  11. data/ext/google/protobuf_c/message.c +264 -238
  12. data/ext/google/protobuf_c/message.h +11 -33
  13. data/ext/google/protobuf_c/protobuf.c +63 -187
  14. data/ext/google/protobuf_c/protobuf.h +27 -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 +13783 -8236
  18. data/ext/google/protobuf_c/ruby-upb.h +14077 -4495
  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/LICENSE +1 -0
  24. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
  25. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +20 -7
  26. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  27. data/lib/google/protobuf/any_pb.rb +6 -8
  28. data/lib/google/protobuf/api_pb.rb +6 -26
  29. data/lib/google/protobuf/descriptor_pb.rb +23 -226
  30. data/lib/google/protobuf/duration_pb.rb +6 -8
  31. data/lib/google/protobuf/empty_pb.rb +6 -6
  32. data/lib/google/protobuf/ffi/descriptor.rb +165 -0
  33. data/lib/google/protobuf/ffi/descriptor_pool.rb +77 -0
  34. data/lib/google/protobuf/ffi/enum_descriptor.rb +173 -0
  35. data/lib/google/protobuf/ffi/ffi.rb +215 -0
  36. data/lib/google/protobuf/ffi/field_descriptor.rb +330 -0
  37. data/lib/google/protobuf/ffi/file_descriptor.rb +49 -0
  38. data/lib/google/protobuf/ffi/internal/arena.rb +60 -0
  39. data/lib/google/protobuf/ffi/internal/convert.rb +296 -0
  40. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  41. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  42. data/lib/google/protobuf/ffi/map.rb +433 -0
  43. data/lib/google/protobuf/ffi/message.rb +785 -0
  44. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  45. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  46. data/lib/google/protobuf/ffi/oneof_descriptor.rb +97 -0
  47. data/lib/google/protobuf/ffi/repeated_field.rb +411 -0
  48. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  49. data/lib/google/protobuf/field_mask_pb.rb +6 -7
  50. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  51. data/lib/google/protobuf/message_exts.rb +8 -26
  52. data/lib/google/protobuf/plugin_pb.rb +25 -0
  53. data/lib/google/protobuf/repeated_field.rb +7 -31
  54. data/lib/google/protobuf/source_context_pb.rb +6 -7
  55. data/lib/google/protobuf/struct_pb.rb +6 -23
  56. data/lib/google/protobuf/timestamp_pb.rb +6 -8
  57. data/lib/google/protobuf/type_pb.rb +6 -71
  58. data/lib/google/protobuf/well_known_types.rb +5 -34
  59. data/lib/google/protobuf/wrappers_pb.rb +6 -31
  60. data/lib/google/protobuf.rb +27 -45
  61. data/lib/google/protobuf_ffi.rb +51 -0
  62. data/lib/google/protobuf_native.rb +19 -0
  63. data/lib/google/tasks/ffi.rake +100 -0
  64. metadata +92 -16
  65. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  66. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  67. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  68. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  69. data/tests/basic.rb +0 -739
  70. data/tests/generated_code_test.rb +0 -23
  71. 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*
@@ -63,10 +44,12 @@ static void Message_mark(void* _self) {
63
44
  rb_gc_mark(self->arena);
64
45
  }
65
46
 
47
+ static size_t Message_memsize(const void* _self) { return sizeof(Message); }
48
+
66
49
  static rb_data_type_t Message_type = {
67
- "Message",
68
- {Message_mark, RUBY_DEFAULT_FREE, NULL},
69
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
50
+ "Google::Protobuf::Message",
51
+ {Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
52
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
70
53
  };
71
54
 
72
55
  static Message* ruby_to_Message(VALUE msg_rb) {
@@ -97,15 +80,19 @@ const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
97
80
  }
98
81
 
99
82
  upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
100
- rb_check_frozen(msg_rb);
101
- 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;
102
86
  }
103
87
 
104
- 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);
105
90
  Message* self = ruby_to_Message(self_);
106
91
  self->msg = msg;
107
- self->arena = arena;
108
- ObjectCache_Add(msg, self_);
92
+ RB_OBJ_WRITE(self_, &self->arena, arena);
93
+ VALUE stored = ObjectCache_TryAdd(msg, self_);
94
+ (void)stored;
95
+ PBRUBY_ASSERT(stored == self_);
109
96
  }
110
97
 
111
98
  VALUE Message_GetArena(VALUE msg_rb) {
@@ -120,7 +107,7 @@ void Message_CheckClass(VALUE klass) {
120
107
  }
121
108
  }
122
109
 
123
- VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
110
+ VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
124
111
  VALUE arena) {
125
112
  if (msg == NULL) return Qnil;
126
113
 
@@ -131,7 +118,6 @@ VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
131
118
  val = Message_alloc(klass);
132
119
  Message_InitPtr(val, msg, arena);
133
120
  }
134
-
135
121
  return val;
136
122
  }
137
123
 
@@ -145,7 +131,8 @@ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
145
131
  for (int i = 0; i < n; i++) {
146
132
  const upb_FieldDef* field = upb_MessageDef_Field(m, i);
147
133
 
148
- if (upb_FieldDef_HasPresence(field) && !upb_Message_Has(msg, field)) {
134
+ if (upb_FieldDef_HasPresence(field) &&
135
+ !upb_Message_HasFieldByDef(msg, field)) {
149
136
  continue;
150
137
  }
151
138
 
@@ -155,7 +142,7 @@ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
155
142
  first = false;
156
143
  }
157
144
 
158
- upb_MessageValue msgval = upb_Message_Get(msg, field);
145
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field);
159
146
 
160
147
  StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field));
161
148
 
@@ -241,15 +228,6 @@ static int extract_method_call(VALUE method_name, Message* self,
241
228
  if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
242
229
  if (Match(m, name, f, o, "has_", "?") &&
243
230
  (*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
231
  return METHOD_PRESENCE;
254
232
  }
255
233
  if (Match(m, name, f, o, "", "_as_value") && *f &&
@@ -271,14 +249,15 @@ static int extract_method_call(VALUE method_name, Message* self,
271
249
  static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
272
250
  int accessor_type) {
273
251
  Message* self = ruby_to_Message(_self);
274
- const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
252
+ const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o);
275
253
 
276
254
  switch (accessor_type) {
277
255
  case METHOD_PRESENCE:
278
256
  return oneof_field == NULL ? Qfalse : Qtrue;
279
257
  case METHOD_CLEAR:
280
258
  if (oneof_field != NULL) {
281
- upb_Message_ClearField(Message_GetMutable(_self, NULL), oneof_field);
259
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL),
260
+ oneof_field);
282
261
  }
283
262
  return Qnil;
284
263
  case METHOD_GETTER:
@@ -301,22 +280,51 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
301
280
  } else {
302
281
  if (val == Qnil &&
303
282
  (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) {
304
- upb_Message_ClearField(msg, f);
283
+ upb_Message_ClearFieldByDef(msg, f);
305
284
  return;
306
285
  }
307
286
  msgval =
308
287
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
309
288
  }
310
- upb_Message_Set(msg, f, msgval, arena);
289
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
290
+ }
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;
311
320
  }
312
321
 
313
322
  VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
314
323
  Message* self = ruby_to_Message(_self);
315
- // This is a special-case: upb_Message_Mutable() for map & array are logically
316
- // const (they will not change what is serialized) but physically
317
- // non-const, as they do allocate a repeated field or map. The logical
318
- // constness means it's ok to do even if the message is frozen.
319
- 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);
320
328
  upb_Arena* arena = Arena_get(self->arena);
321
329
  if (upb_FieldDef_IsMap(f)) {
322
330
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
@@ -329,12 +337,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
329
337
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
330
338
  return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
331
339
  } else if (upb_FieldDef_IsSubMessage(f)) {
332
- if (!upb_Message_Has(self->msg, f)) return Qnil;
340
+ if (!upb_Message_HasFieldByDef(msg, f)) return Qnil;
333
341
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
334
342
  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
335
343
  return Message_GetRubyWrapper(submsg, m, self->arena);
336
344
  } else {
337
- upb_MessageValue msgval = upb_Message_Get(self->msg, f);
345
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
338
346
  return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
339
347
  }
340
348
  }
@@ -348,23 +356,24 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
348
356
  Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
349
357
  return Qnil;
350
358
  case METHOD_CLEAR:
351
- upb_Message_ClearField(Message_GetMutable(_self, NULL), f);
359
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f);
352
360
  return Qnil;
353
361
  case METHOD_PRESENCE:
354
362
  if (!upb_FieldDef_HasPresence(f)) {
355
363
  rb_raise(rb_eRuntimeError, "Field does not have presence.");
356
364
  }
357
- return upb_Message_Has(Message_Get(_self, NULL), f);
365
+ return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f);
358
366
  case METHOD_WRAPPER_GETTER: {
359
367
  Message* self = ruby_to_Message(_self);
360
- if (upb_Message_Has(self->msg, f)) {
368
+ if (upb_Message_HasFieldByDef(self->msg, f)) {
361
369
  PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
362
370
  !upb_FieldDef_IsRepeated(f));
363
- upb_MessageValue wrapper = upb_Message_Get(self->msg, f);
371
+ upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f);
364
372
  const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
365
373
  const upb_FieldDef* value_f =
366
374
  upb_MessageDef_FindFieldByNumber(wrapper_m, 1);
367
- upb_MessageValue value = upb_Message_Get(wrapper.msg_val, value_f);
375
+ upb_MessageValue value =
376
+ upb_Message_GetFieldByDef(wrapper.msg_val, value_f);
368
377
  return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
369
378
  } else {
370
379
  return Qnil;
@@ -373,19 +382,20 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
373
382
  case METHOD_WRAPPER_SETTER: {
374
383
  upb_Message* msg = Message_GetMutable(_self, NULL);
375
384
  if (argv[1] == Qnil) {
376
- upb_Message_ClearField(msg, f);
385
+ upb_Message_ClearFieldByDef(msg, f);
377
386
  } else {
378
387
  const upb_FieldDef* val_f =
379
388
  upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1);
380
389
  upb_MessageValue msgval = Convert_RubyToUpb(
381
390
  argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
382
391
  upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
383
- upb_Message_Set(wrapper, val_f, msgval, arena);
392
+ upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
384
393
  }
385
394
  return Qnil;
386
395
  }
387
396
  case METHOD_ENUM_GETTER: {
388
- upb_MessageValue msgval = upb_Message_Get(Message_Get(_self, NULL), f);
397
+ upb_MessageValue msgval =
398
+ upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
389
399
 
390
400
  if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
391
401
  // Map repeated fields to a new type with ints
@@ -456,7 +466,6 @@ static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
456
466
  if (argc != 2) {
457
467
  rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
458
468
  }
459
- rb_check_frozen(_self);
460
469
  break;
461
470
  default:
462
471
  if (argc != 1) {
@@ -510,8 +519,9 @@ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
510
519
  k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
511
520
 
512
521
  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);
522
+ const upb_MiniTable* t =
523
+ upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
524
+ upb_Message* msg = upb_Message_New(t, map_init->arena);
515
525
  Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
516
526
  map_init->arena);
517
527
  v.msg_val = msg;
@@ -541,7 +551,8 @@ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
541
551
  upb_Arena* arena) {
542
552
  if (info.type == kUpb_CType_Message) {
543
553
  upb_MessageValue msgval;
544
- upb_Message* msg = upb_Message_New(info.def.msgdef, arena);
554
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
555
+ upb_Message* msg = upb_Message_New(t, arena);
545
556
  Message_InitFromValue(msg, info.def.msgdef, val, arena);
546
557
  msgval.msg_val = msg;
547
558
  return msgval;
@@ -593,7 +604,7 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
593
604
  } else {
594
605
  upb_MessageValue msgval =
595
606
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
596
- upb_Message_Set(msg, f, msgval, arena);
607
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
597
608
  }
598
609
  }
599
610
 
@@ -656,7 +667,8 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
656
667
  Message* self = ruby_to_Message(_self);
657
668
  VALUE arena_rb = Arena_new();
658
669
  upb_Arena* arena = Arena_get(arena_rb);
659
- upb_Message* msg = upb_Message_New(self->msgdef, arena);
670
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
671
+ upb_Message* msg = upb_Message_New(t, arena);
660
672
 
661
673
  Message_InitPtr(_self, msg, arena_rb);
662
674
 
@@ -680,39 +692,12 @@ static VALUE Message_dup(VALUE _self) {
680
692
  Message* self = ruby_to_Message(_self);
681
693
  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
682
694
  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);
695
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
696
+ upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
688
697
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
689
698
  return new_msg;
690
699
  }
691
700
 
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 = 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;
710
- } else {
711
- upb_Arena_Free(arena_tmp);
712
- rb_raise(cParseError, "Error comparing messages");
713
- }
714
- }
715
-
716
701
  /*
717
702
  * call-seq:
718
703
  * Message.==(other) => boolean
@@ -729,27 +714,22 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
729
714
  Message* other = ruby_to_Message(_other);
730
715
  assert(self->msgdef == other->msgdef);
731
716
 
732
- 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;
733
721
  }
734
722
 
735
723
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
736
724
  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;
725
+ upb_Status status;
726
+ upb_Status_Clear(&status);
727
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
728
+ if (upb_Status_IsOk(&status)) {
729
+ return return_value;
750
730
  } else {
751
- upb_Arena_Free(arena);
752
- rb_raise(cParseError, "Error calculating hash");
731
+ rb_raise(cParseError, "Message_Hash(): %s",
732
+ upb_Status_ErrorMessage(&status));
753
733
  }
754
734
  }
755
735
 
@@ -806,57 +786,34 @@ static VALUE Message_CreateHash(const upb_Message* msg,
806
786
  if (!msg) return Qnil;
807
787
 
808
788
  VALUE hash = rb_hash_new();
809
- int n = upb_MessageDef_FieldCount(m);
810
- bool is_proto2;
811
-
812
- // We currently have a few behaviors that are specific to proto2.
813
- // This is unfortunate, we should key behaviors off field attributes (like
814
- // whether a field has presence), not proto2 vs. proto3. We should see if we
815
- // can change this without breaking users.
816
- is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
817
-
818
- for (int i = 0; i < n; i++) {
819
- const upb_FieldDef* field = upb_MessageDef_Field(m, i);
820
- TypeInfo type_info = TypeInfo_get(field);
821
- upb_MessageValue msgval;
822
- VALUE msg_value;
823
- VALUE msg_key;
824
-
825
- if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
826
- !upb_FieldDef_IsRepeated(field) && !upb_Message_Has(msg, field)) {
827
- // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
828
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
829
- rb_hash_aset(hash, msg_key, Qnil);
830
- continue;
831
- }
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;
832
793
 
833
- // Do not include fields that are not present (oneof or optional fields).
834
- if (is_proto2 && upb_FieldDef_HasPresence(field) &&
835
- !upb_Message_Has(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]"
836
798
  continue;
837
799
  }
838
800
 
839
- msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
840
- msgval = upb_Message_Get(msg, field);
841
-
842
- // Proto2 omits empty map/repeated filds also.
801
+ TypeInfo type_info = TypeInfo_get(field);
802
+ VALUE msg_value;
843
803
 
844
804
  if (upb_FieldDef_IsMap(field)) {
845
805
  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
846
806
  const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
847
807
  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
848
808
  upb_CType key_type = upb_FieldDef_CType(key_f);
849
- 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));
850
810
  } else if (upb_FieldDef_IsRepeated(field)) {
851
- if (is_proto2 &&
852
- (!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
853
- continue;
854
- }
855
- msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
811
+ msg_value = RepeatedField_CreateArray(val.array_val, type_info);
856
812
  } else {
857
- msg_value = Scalar_CreateHash(msgval, type_info);
813
+ msg_value = Scalar_CreateHash(val, type_info);
858
814
  }
859
815
 
816
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
860
817
  rb_hash_aset(hash, msg_key, msg_value);
861
818
  }
862
819
 
@@ -882,19 +839,44 @@ static VALUE Message_to_h(VALUE _self) {
882
839
  return Message_CreateHash(self->msg, self->msgdef);
883
840
  }
884
841
 
842
+ /*
843
+ * call-seq:
844
+ * Message.frozen? => bool
845
+ *
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.
849
+ */
850
+ VALUE Message_frozen(VALUE _self) {
851
+ Message* self = ruby_to_Message(_self);
852
+ if (!upb_Message_IsFrozen(self->msg)) {
853
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
854
+ return Qfalse;
855
+ }
856
+
857
+ // Lazily freeze the Ruby wrapper.
858
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
859
+ return Qtrue;
860
+ }
861
+
885
862
  /*
886
863
  * call-seq:
887
864
  * Message.freeze => self
888
865
  *
889
- * Freezes the message object. We have to intercept this so we can pin the
890
- * Ruby object into memory so we don't forget it's frozen.
866
+ * Freezes the message object. We have to intercept this so we can freeze the
867
+ * underlying representation, not just the Ruby wrapper.
891
868
  */
892
- static VALUE Message_freeze(VALUE _self) {
869
+ VALUE Message_freeze(VALUE _self) {
893
870
  Message* self = ruby_to_Message(_self);
894
- if (!RB_OBJ_FROZEN(_self)) {
895
- Arena_Pin(self->arena, _self);
896
- RB_OBJ_FREEZE(_self);
871
+ if (RB_OBJ_FROZEN(_self)) {
872
+ PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg));
873
+ return _self;
897
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);
898
880
  return _self;
899
881
  }
900
882
 
@@ -940,7 +922,7 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
940
922
  }
941
923
 
942
924
  val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
943
- upb_Message_Set(Message_GetMutable(_self, NULL), f, val, arena);
925
+ upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
944
926
 
945
927
  return Qnil;
946
928
  }
@@ -950,7 +932,7 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
950
932
  * MessageClass.decode(data, options) => message
951
933
  *
952
934
  * 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
935
+ * format) under the interpretation given by this message class's definition
954
936
  * and returns a message object with the corresponding field values.
955
937
  * @param options [Hash] options for the decoder
956
938
  * recursion_limit: set to maximum decoding depth for message (default is 64)
@@ -969,10 +951,11 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
969
951
  rb_raise(rb_eArgError, "Expected hash arguments.");
970
952
  }
971
953
 
972
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
954
+ VALUE depth =
955
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
973
956
 
974
957
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
975
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
958
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
976
959
  }
977
960
  }
978
961
 
@@ -980,17 +963,27 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
980
963
  rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
981
964
  }
982
965
 
966
+ return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options,
967
+ klass, /*freeze*/ false);
968
+ }
969
+
970
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
971
+ VALUE klass, bool freeze) {
983
972
  VALUE msg_rb = initialize_rb_class_with_no_args(klass);
984
973
  Message* msg = ruby_to_Message(msg_rb);
985
974
 
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
-
975
+ const upb_FileDef* file = upb_MessageDef_File(msg->msgdef);
976
+ const upb_ExtensionRegistry* extreg =
977
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
978
+ upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
979
+ upb_MessageDef_MiniTable(msg->msgdef),
980
+ extreg, options, Arena_get(msg->arena));
990
981
  if (status != kUpb_DecodeStatus_Ok) {
991
982
  rb_raise(cParseError, "Error occurred during parsing");
992
983
  }
993
-
984
+ if (freeze) {
985
+ Message_freeze(msg_rb);
986
+ }
994
987
  return msg_rb;
995
988
  }
996
989
 
@@ -1011,9 +1004,6 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1011
1004
  int options = 0;
1012
1005
  upb_Status status;
1013
1006
 
1014
- // TODO(haberman): use this message's pool instead.
1015
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1016
-
1017
1007
  if (argc < 1 || argc > 2) {
1018
1008
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1019
1009
  }
@@ -1034,7 +1024,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1034
1024
  rb_raise(rb_eArgError, "Expected string for JSON data.");
1035
1025
  }
1036
1026
 
1037
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
1027
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1038
1028
  // convert, because string handlers pass data directly to message string
1039
1029
  // fields.
1040
1030
 
@@ -1047,11 +1037,22 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1047
1037
  }
1048
1038
 
1049
1039
  upb_Status_Clear(&status);
1050
- if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
1051
- (upb_Message*)msg->msg, msg->msgdef, symtab, options,
1052
- Arena_get(msg->arena), &status)) {
1053
- rb_raise(cParseError, "Error occurred during parsing: %s",
1054
- upb_Status_ErrorMessage(&status));
1040
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1041
+
1042
+ int result = upb_JsonDecodeDetectingNonconformance(
1043
+ RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
1044
+ msg->msgdef, pool, options, Arena_get(msg->arena), &status);
1045
+
1046
+ switch (result) {
1047
+ case kUpb_JsonDecodeResult_Ok:
1048
+ break;
1049
+ case kUpb_JsonDecodeResult_OkWithEmptyStringNumerics:
1050
+ rb_warn("%s", upb_Status_ErrorMessage(&status));
1051
+ break;
1052
+ case kUpb_JsonDecodeResult_Error:
1053
+ rb_raise(cParseError, "Error occurred during parsing: %s",
1054
+ upb_Status_ErrorMessage(&status));
1055
+ break;
1055
1056
  }
1056
1057
 
1057
1058
  return msg_rb;
@@ -1069,7 +1070,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1069
1070
  static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1070
1071
  Message* msg = ruby_to_Message(argv[0]);
1071
1072
  int options = 0;
1072
- const char* data;
1073
+ char* data;
1073
1074
  size_t size;
1074
1075
 
1075
1076
  if (CLASS_OF(argv[0]) != klass) {
@@ -1085,19 +1086,21 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1085
1086
  if (TYPE(hash_args) != T_HASH) {
1086
1087
  rb_raise(rb_eArgError, "Expected hash arguments.");
1087
1088
  }
1088
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1089
+ VALUE depth =
1090
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1089
1091
 
1090
1092
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1091
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
1093
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1092
1094
  }
1093
1095
  }
1094
1096
 
1095
- upb_Arena *arena = upb_Arena_New();
1097
+ upb_Arena* arena = upb_Arena_New();
1096
1098
 
1097
- data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef),
1098
- options, arena, &size);
1099
+ upb_EncodeStatus status =
1100
+ upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
1101
+ arena, &data, &size);
1099
1102
 
1100
- if (data) {
1103
+ if (status == kUpb_EncodeStatus_Ok) {
1101
1104
  VALUE ret = rb_str_new(data, size);
1102
1105
  rb_enc_associate(ret, rb_ascii8bit_encoding());
1103
1106
  upb_Arena_Free(arena);
@@ -1125,9 +1128,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1125
1128
  size_t size;
1126
1129
  upb_Status status;
1127
1130
 
1128
- // TODO(haberman): use this message's pool instead.
1129
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1130
-
1131
1131
  if (argc < 1 || argc > 2) {
1132
1132
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1133
1133
  }
@@ -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,11 +1153,18 @@ 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);
1158
- size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
1159
- sizeof(buf), &status);
1165
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1166
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1167
+ &status);
1160
1168
 
1161
1169
  if (!upb_Status_IsOk(&status)) {
1162
1170
  rb_raise(cParseError, "Error occurred during encoding: %s",
@@ -1166,7 +1174,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1166
1174
  VALUE ret;
1167
1175
  if (size >= sizeof(buf)) {
1168
1176
  char* buf2 = malloc(size + 1);
1169
- upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
1177
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1170
1178
  &status);
1171
1179
  ret = rb_str_new(buf2, size);
1172
1180
  free(buf2);
@@ -1201,36 +1209,8 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
1201
1209
  klass = rb_define_class_id(
1202
1210
  // Docs say this parameter is ignored. User will assign return value to
1203
1211
  // their own toplevel constant class name.
1204
- rb_intern("Message"), rb_cObject);
1212
+ rb_intern("Message"), cAbstractMessage);
1205
1213
  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
1214
  return klass;
1235
1215
  }
1236
1216
 
@@ -1290,15 +1270,22 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1290
1270
  int n = upb_EnumDef_ValueCount(e);
1291
1271
  for (int i = 0; i < n; i++) {
1292
1272
  const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
1293
- const char* name = upb_EnumValueDef_Name(ev);
1273
+ upb_Arena* arena = upb_Arena_New();
1274
+ const char* src_name = upb_EnumValueDef_Name(ev);
1275
+ char* name = upb_strdup2(src_name, strlen(src_name), arena);
1294
1276
  int32_t value = upb_EnumValueDef_Number(ev);
1295
1277
  if (name[0] < 'A' || name[0] > 'Z') {
1296
- rb_warn(
1297
- "Enum value '%s' does not start with an uppercase letter "
1298
- "as is required for Ruby constants.",
1299
- name);
1278
+ if (name[0] >= 'a' && name[0] <= 'z') {
1279
+ name[0] -= 32; // auto capitalize
1280
+ } else {
1281
+ rb_warn(
1282
+ "Enum value '%s' does not start with an uppercase letter "
1283
+ "as is required for Ruby constants.",
1284
+ name);
1285
+ }
1300
1286
  }
1301
1287
  rb_define_const(mod, name, INT2NUM(value));
1288
+ upb_Arena_Free(arena);
1302
1289
  }
1303
1290
 
1304
1291
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
@@ -1309,7 +1296,7 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1309
1296
  return mod;
1310
1297
  }
1311
1298
 
1312
- // Internal only; used by Google::Protobuf.deep_copy.
1299
+ // Internal to the library; used by Google::Protobuf.deep_copy.
1313
1300
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1314
1301
  upb_Arena* arena) {
1315
1302
  // Serialize and parse.
@@ -1317,11 +1304,16 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1317
1304
  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1318
1305
  size_t size;
1319
1306
 
1320
- char* data = upb_Encode(msg, layout, 0, tmp_arena, &size);
1321
- upb_Message* new_msg = upb_Message_New(m, arena);
1307
+ upb_Message* new_msg = upb_Message_New(layout, arena);
1308
+ char* data;
1322
1309
 
1323
- if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
1324
- kUpb_DecodeStatus_Ok) {
1310
+ const upb_FileDef* file = upb_MessageDef_File(m);
1311
+ const upb_ExtensionRegistry* extreg =
1312
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1313
+ if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1314
+ kUpb_EncodeStatus_Ok ||
1315
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1316
+ kUpb_DecodeStatus_Ok) {
1325
1317
  upb_Arena_Free(tmp_arena);
1326
1318
  rb_raise(cParseError, "Error occurred copying proto");
1327
1319
  }
@@ -1348,7 +1340,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1348
1340
  switch (upb_MessageDef_WellKnownType(m)) {
1349
1341
  case kUpb_WellKnown_Timestamp: {
1350
1342
  // Time -> Google::Protobuf::Timestamp
1351
- upb_Message* msg = upb_Message_New(m, arena);
1343
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1344
+ upb_Message* msg = upb_Message_New(t, arena);
1352
1345
  upb_MessageValue sec, nsec;
1353
1346
  struct timespec time;
1354
1347
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
@@ -1359,13 +1352,14 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1359
1352
  time = rb_time_timespec(value);
1360
1353
  sec.int64_val = time.tv_sec;
1361
1354
  nsec.int32_val = time.tv_nsec;
1362
- upb_Message_Set(msg, sec_f, sec, arena);
1363
- upb_Message_Set(msg, nsec_f, nsec, arena);
1355
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1356
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1364
1357
  return msg;
1365
1358
  }
1366
1359
  case kUpb_WellKnown_Duration: {
1367
1360
  // Numeric -> Google::Protobuf::Duration
1368
- upb_Message* msg = upb_Message_New(m, arena);
1361
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1362
+ upb_Message* msg = upb_Message_New(t, arena);
1369
1363
  upb_MessageValue sec, nsec;
1370
1364
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1371
1365
  const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
@@ -1374,8 +1368,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1374
1368
 
1375
1369
  sec.int64_val = NUM2LL(value);
1376
1370
  nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
1377
- upb_Message_Set(msg, sec_f, sec, arena);
1378
- upb_Message_Set(msg, nsec_f, nsec, arena);
1371
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1372
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1379
1373
  return msg;
1380
1374
  }
1381
1375
  default:
@@ -1392,11 +1386,43 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1392
1386
  return self->msg;
1393
1387
  }
1394
1388
 
1389
+ static void Message_define_class(VALUE klass) {
1390
+ rb_define_alloc_func(klass, Message_alloc);
1391
+
1392
+ rb_require("google/protobuf/message_exts");
1393
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
1394
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1395
+ -1);
1396
+ rb_define_method(klass, "initialize", Message_initialize, -1);
1397
+ rb_define_method(klass, "dup", Message_dup, 0);
1398
+ // Also define #clone so that we don't inherit Object#clone.
1399
+ rb_define_method(klass, "clone", Message_dup, 0);
1400
+ rb_define_method(klass, "==", Message_eq, 1);
1401
+ rb_define_method(klass, "eql?", Message_eq, 1);
1402
+ rb_define_method(klass, "freeze", Message_freeze, 0);
1403
+ rb_define_method(klass, "frozen?", Message_frozen, 0);
1404
+ rb_define_method(klass, "hash", Message_hash, 0);
1405
+ rb_define_method(klass, "to_h", Message_to_h, 0);
1406
+ rb_define_method(klass, "inspect", Message_inspect, 0);
1407
+ rb_define_method(klass, "to_s", Message_inspect, 0);
1408
+ rb_define_method(klass, "[]", Message_index, 1);
1409
+ rb_define_method(klass, "[]=", Message_index_set, 2);
1410
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
1411
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
1412
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1413
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1414
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1415
+ }
1416
+
1395
1417
  void Message_register(VALUE protobuf) {
1396
1418
  cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
1419
+ cAbstractMessage =
1420
+ rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
1421
+ Message_define_class(cAbstractMessage);
1422
+ rb_gc_register_address(&cAbstractMessage);
1397
1423
 
1398
1424
  // Ruby-interned string: "descriptor". We use this identifier to store an
1399
1425
  // instance variable on message classes we create in order to link them back
1400
1426
  // to their descriptors.
1401
- descriptor_instancevar_interned = rb_intern("descriptor");
1427
+ descriptor_instancevar_interned = rb_intern("@descriptor");
1402
1428
  }