google-protobuf 3.21.0 → 4.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (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 +537 -75
  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 +250 -234
  12. data/ext/google/protobuf_c/message.h +11 -33
  13. data/ext/google/protobuf_c/protobuf.c +63 -185
  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 +14513 -9003
  18. data/ext/google/protobuf_c/ruby-upb.h +13990 -4496
  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 +210 -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 +781 -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,8 +1037,9 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1047
1037
  }
1048
1038
 
1049
1039
  upb_Status_Clear(&status);
1040
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1050
1041
  if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
1051
- (upb_Message*)msg->msg, msg->msgdef, symtab, options,
1042
+ (upb_Message*)msg->msg, msg->msgdef, pool, options,
1052
1043
  Arena_get(msg->arena), &status)) {
1053
1044
  rb_raise(cParseError, "Error occurred during parsing: %s",
1054
1045
  upb_Status_ErrorMessage(&status));
@@ -1069,7 +1060,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1069
1060
  static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1070
1061
  Message* msg = ruby_to_Message(argv[0]);
1071
1062
  int options = 0;
1072
- const char* data;
1063
+ char* data;
1073
1064
  size_t size;
1074
1065
 
1075
1066
  if (CLASS_OF(argv[0]) != klass) {
@@ -1085,19 +1076,21 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1085
1076
  if (TYPE(hash_args) != T_HASH) {
1086
1077
  rb_raise(rb_eArgError, "Expected hash arguments.");
1087
1078
  }
1088
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1079
+ VALUE depth =
1080
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1089
1081
 
1090
1082
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1091
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
1083
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1092
1084
  }
1093
1085
  }
1094
1086
 
1095
- upb_Arena *arena = upb_Arena_New();
1087
+ upb_Arena* arena = upb_Arena_New();
1096
1088
 
1097
- data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef),
1098
- options, arena, &size);
1089
+ upb_EncodeStatus status =
1090
+ upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
1091
+ arena, &data, &size);
1099
1092
 
1100
- if (data) {
1093
+ if (status == kUpb_EncodeStatus_Ok) {
1101
1094
  VALUE ret = rb_str_new(data, size);
1102
1095
  rb_enc_associate(ret, rb_ascii8bit_encoding());
1103
1096
  upb_Arena_Free(arena);
@@ -1125,9 +1118,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1125
1118
  size_t size;
1126
1119
  upb_Status status;
1127
1120
 
1128
- // TODO(haberman): use this message's pool instead.
1129
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1130
-
1131
1121
  if (argc < 1 || argc > 2) {
1132
1122
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1133
1123
  }
@@ -1135,7 +1125,8 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1135
1125
  if (argc == 2) {
1136
1126
  VALUE hash_args = argv[1];
1137
1127
  if (TYPE(hash_args) != T_HASH) {
1138
- if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, rb_str_new2("to_h")))) {
1128
+ if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1,
1129
+ rb_str_new2("to_h")))) {
1139
1130
  hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0);
1140
1131
  } else {
1141
1132
  rb_raise(rb_eArgError, "Expected hash arguments.");
@@ -1152,11 +1143,18 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1152
1143
  Qfalse))) {
1153
1144
  options |= upb_JsonEncode_EmitDefaults;
1154
1145
  }
1146
+
1147
+ if (RTEST(rb_hash_lookup2(hash_args,
1148
+ ID2SYM(rb_intern("format_enums_as_integers")),
1149
+ Qfalse))) {
1150
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
1151
+ }
1155
1152
  }
1156
1153
 
1157
1154
  upb_Status_Clear(&status);
1158
- size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
1159
- sizeof(buf), &status);
1155
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1156
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1157
+ &status);
1160
1158
 
1161
1159
  if (!upb_Status_IsOk(&status)) {
1162
1160
  rb_raise(cParseError, "Error occurred during encoding: %s",
@@ -1166,7 +1164,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1166
1164
  VALUE ret;
1167
1165
  if (size >= sizeof(buf)) {
1168
1166
  char* buf2 = malloc(size + 1);
1169
- upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
1167
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1170
1168
  &status);
1171
1169
  ret = rb_str_new(buf2, size);
1172
1170
  free(buf2);
@@ -1201,36 +1199,8 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
1201
1199
  klass = rb_define_class_id(
1202
1200
  // Docs say this parameter is ignored. User will assign return value to
1203
1201
  // their own toplevel constant class name.
1204
- rb_intern("Message"), rb_cObject);
1202
+ rb_intern("Message"), cAbstractMessage);
1205
1203
  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
1204
  return klass;
1235
1205
  }
1236
1206
 
@@ -1290,15 +1260,22 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1290
1260
  int n = upb_EnumDef_ValueCount(e);
1291
1261
  for (int i = 0; i < n; i++) {
1292
1262
  const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
1293
- const char* name = upb_EnumValueDef_Name(ev);
1263
+ upb_Arena* arena = upb_Arena_New();
1264
+ const char* src_name = upb_EnumValueDef_Name(ev);
1265
+ char* name = upb_strdup2(src_name, strlen(src_name), arena);
1294
1266
  int32_t value = upb_EnumValueDef_Number(ev);
1295
1267
  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);
1268
+ if (name[0] >= 'a' && name[0] <= 'z') {
1269
+ name[0] -= 32; // auto capitalize
1270
+ } else {
1271
+ rb_warn(
1272
+ "Enum value '%s' does not start with an uppercase letter "
1273
+ "as is required for Ruby constants.",
1274
+ name);
1275
+ }
1300
1276
  }
1301
1277
  rb_define_const(mod, name, INT2NUM(value));
1278
+ upb_Arena_Free(arena);
1302
1279
  }
1303
1280
 
1304
1281
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
@@ -1309,7 +1286,7 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1309
1286
  return mod;
1310
1287
  }
1311
1288
 
1312
- // Internal only; used by Google::Protobuf.deep_copy.
1289
+ // Internal to the library; used by Google::Protobuf.deep_copy.
1313
1290
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1314
1291
  upb_Arena* arena) {
1315
1292
  // Serialize and parse.
@@ -1317,11 +1294,16 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1317
1294
  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1318
1295
  size_t size;
1319
1296
 
1320
- char* data = upb_Encode(msg, layout, 0, tmp_arena, &size);
1321
- upb_Message* new_msg = upb_Message_New(m, arena);
1297
+ upb_Message* new_msg = upb_Message_New(layout, arena);
1298
+ char* data;
1322
1299
 
1323
- if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
1324
- kUpb_DecodeStatus_Ok) {
1300
+ const upb_FileDef* file = upb_MessageDef_File(m);
1301
+ const upb_ExtensionRegistry* extreg =
1302
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1303
+ if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1304
+ kUpb_EncodeStatus_Ok ||
1305
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1306
+ kUpb_DecodeStatus_Ok) {
1325
1307
  upb_Arena_Free(tmp_arena);
1326
1308
  rb_raise(cParseError, "Error occurred copying proto");
1327
1309
  }
@@ -1348,7 +1330,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1348
1330
  switch (upb_MessageDef_WellKnownType(m)) {
1349
1331
  case kUpb_WellKnown_Timestamp: {
1350
1332
  // Time -> Google::Protobuf::Timestamp
1351
- upb_Message* msg = upb_Message_New(m, arena);
1333
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1334
+ upb_Message* msg = upb_Message_New(t, arena);
1352
1335
  upb_MessageValue sec, nsec;
1353
1336
  struct timespec time;
1354
1337
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
@@ -1359,13 +1342,14 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1359
1342
  time = rb_time_timespec(value);
1360
1343
  sec.int64_val = time.tv_sec;
1361
1344
  nsec.int32_val = time.tv_nsec;
1362
- upb_Message_Set(msg, sec_f, sec, arena);
1363
- upb_Message_Set(msg, nsec_f, nsec, arena);
1345
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1346
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1364
1347
  return msg;
1365
1348
  }
1366
1349
  case kUpb_WellKnown_Duration: {
1367
1350
  // Numeric -> Google::Protobuf::Duration
1368
- upb_Message* msg = upb_Message_New(m, arena);
1351
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1352
+ upb_Message* msg = upb_Message_New(t, arena);
1369
1353
  upb_MessageValue sec, nsec;
1370
1354
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1371
1355
  const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
@@ -1374,8 +1358,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1374
1358
 
1375
1359
  sec.int64_val = NUM2LL(value);
1376
1360
  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);
1361
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1362
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1379
1363
  return msg;
1380
1364
  }
1381
1365
  default:
@@ -1392,11 +1376,43 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1392
1376
  return self->msg;
1393
1377
  }
1394
1378
 
1379
+ static void Message_define_class(VALUE klass) {
1380
+ rb_define_alloc_func(klass, Message_alloc);
1381
+
1382
+ rb_require("google/protobuf/message_exts");
1383
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
1384
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1385
+ -1);
1386
+ rb_define_method(klass, "initialize", Message_initialize, -1);
1387
+ rb_define_method(klass, "dup", Message_dup, 0);
1388
+ // Also define #clone so that we don't inherit Object#clone.
1389
+ rb_define_method(klass, "clone", Message_dup, 0);
1390
+ rb_define_method(klass, "==", Message_eq, 1);
1391
+ rb_define_method(klass, "eql?", Message_eq, 1);
1392
+ rb_define_method(klass, "freeze", Message_freeze, 0);
1393
+ rb_define_method(klass, "frozen?", Message_frozen, 0);
1394
+ rb_define_method(klass, "hash", Message_hash, 0);
1395
+ rb_define_method(klass, "to_h", Message_to_h, 0);
1396
+ rb_define_method(klass, "inspect", Message_inspect, 0);
1397
+ rb_define_method(klass, "to_s", Message_inspect, 0);
1398
+ rb_define_method(klass, "[]", Message_index, 1);
1399
+ rb_define_method(klass, "[]=", Message_index_set, 2);
1400
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
1401
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
1402
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1403
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1404
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1405
+ }
1406
+
1395
1407
  void Message_register(VALUE protobuf) {
1396
1408
  cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
1409
+ cAbstractMessage =
1410
+ rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
1411
+ Message_define_class(cAbstractMessage);
1412
+ rb_gc_register_address(&cAbstractMessage);
1397
1413
 
1398
1414
  // Ruby-interned string: "descriptor". We use this identifier to store an
1399
1415
  // instance variable on message classes we create in order to link them back
1400
1416
  // to their descriptors.
1401
- descriptor_instancevar_interned = rb_intern("descriptor");
1417
+ descriptor_instancevar_interned = rb_intern("@descriptor");
1402
1418
  }