google-protobuf 3.20.0 → 4.34.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 (73) 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 +961 -157
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +21 -11
  8. data/ext/google/protobuf_c/glue.c +135 -0
  9. data/ext/google/protobuf_c/map.c +187 -121
  10. data/ext/google/protobuf_c/map.h +12 -30
  11. data/ext/google/protobuf_c/message.c +354 -294
  12. data/ext/google/protobuf_c/message.h +11 -33
  13. data/ext/google/protobuf_c/protobuf.c +65 -188
  14. data/ext/google/protobuf_c/protobuf.h +21 -41
  15. data/ext/google/protobuf_c/repeated_field.c +145 -74
  16. data/ext/google/protobuf_c/repeated_field.h +11 -29
  17. data/ext/google/protobuf_c/ruby-upb.c +15734 -8866
  18. data/ext/google/protobuf_c/ruby-upb.h +16769 -4511
  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 +207 -0
  25. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +20 -7
  26. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
  27. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
  28. data/lib/google/protobuf/any_pb.rb +6 -8
  29. data/lib/google/protobuf/api_pb.rb +6 -26
  30. data/lib/google/protobuf/descriptor_pb.rb +27 -226
  31. data/lib/google/protobuf/duration_pb.rb +6 -8
  32. data/lib/google/protobuf/empty_pb.rb +6 -6
  33. data/lib/google/protobuf/ffi/descriptor.rb +175 -0
  34. data/lib/google/protobuf/ffi/descriptor_pool.rb +83 -0
  35. data/lib/google/protobuf/ffi/enum_descriptor.rb +183 -0
  36. data/lib/google/protobuf/ffi/ffi.rb +213 -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 +6 -7
  51. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  52. data/lib/google/protobuf/message_exts.rb +12 -26
  53. data/lib/google/protobuf/plugin_pb.rb +25 -0
  54. data/lib/google/protobuf/repeated_field.rb +22 -33
  55. data/lib/google/protobuf/source_context_pb.rb +6 -7
  56. data/lib/google/protobuf/struct_pb.rb +6 -23
  57. data/lib/google/protobuf/timestamp_pb.rb +6 -8
  58. data/lib/google/protobuf/type_pb.rb +6 -71
  59. data/lib/google/protobuf/well_known_types.rb +5 -34
  60. data/lib/google/protobuf/wrappers_pb.rb +6 -31
  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 +103 -32
  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/ext/google/protobuf_c/wrap_memcpy.c +0 -52
  70. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  71. data/tests/basic.rb +0 -670
  72. data/tests/generated_code_test.rb +0 -23
  73. 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,25 @@ 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) ? Qtrue
366
+ : Qfalse;
358
367
  case METHOD_WRAPPER_GETTER: {
359
368
  Message* self = ruby_to_Message(_self);
360
- if (upb_Message_Has(self->msg, f)) {
369
+ if (upb_Message_HasFieldByDef(self->msg, f)) {
361
370
  PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
362
371
  !upb_FieldDef_IsRepeated(f));
363
- upb_MessageValue wrapper = upb_Message_Get(self->msg, f);
372
+ upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f);
364
373
  const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
365
374
  const upb_FieldDef* value_f =
366
375
  upb_MessageDef_FindFieldByNumber(wrapper_m, 1);
367
- upb_MessageValue value = upb_Message_Get(wrapper.msg_val, value_f);
376
+ upb_MessageValue value =
377
+ upb_Message_GetFieldByDef(wrapper.msg_val, value_f);
368
378
  return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
369
379
  } else {
370
380
  return Qnil;
@@ -373,21 +383,22 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
373
383
  case METHOD_WRAPPER_SETTER: {
374
384
  upb_Message* msg = Message_GetMutable(_self, NULL);
375
385
  if (argv[1] == Qnil) {
376
- upb_Message_ClearField(msg, f);
386
+ upb_Message_ClearFieldByDef(msg, f);
377
387
  } else {
378
388
  const upb_FieldDef* val_f =
379
389
  upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1);
380
390
  upb_MessageValue msgval = Convert_RubyToUpb(
381
391
  argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
382
392
  upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
383
- upb_Message_Set(wrapper, val_f, msgval, arena);
393
+ upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
384
394
  }
385
395
  return Qnil;
386
396
  }
387
397
  case METHOD_ENUM_GETTER: {
388
- upb_MessageValue msgval = upb_Message_Get(Message_Get(_self, NULL), f);
398
+ upb_MessageValue msgval =
399
+ upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
389
400
 
390
- if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
401
+ if (upb_FieldDef_IsRepeated(f)) {
391
402
  // Map repeated fields to a new type with ints
392
403
  VALUE arr = rb_ary_new();
393
404
  size_t i, n = upb_Array_Size(msgval.array_val);
@@ -409,11 +420,10 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
409
420
  }
410
421
 
411
422
  /*
412
- * call-seq:
413
- * Message.method_missing(*args)
423
+ * ruby-doc: AbstractMessage
414
424
  *
415
- * Provides accessors and setters and methods to clear and check for presence of
416
- * message fields according to their field names.
425
+ * The {AbstractMessage} class is the parent class for all Protobuf messages,
426
+ * and is generated from C code.
417
427
  *
418
428
  * For any field whose name does not conflict with a built-in method, an
419
429
  * accessor is provided with the same name as the field, and a setter is
@@ -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;
@@ -580,7 +591,7 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
580
591
  if (upb_FieldDef_IsMap(f)) {
581
592
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
582
593
  Map_InitFromValue(map, f, val, arena);
583
- } else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
594
+ } else if (upb_FieldDef_IsRepeated(f)) {
584
595
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
585
596
  RepeatedField_InitFromValue(arr, f, val, arena);
586
597
  } else if (upb_FieldDef_IsSubMessage(f)) {
@@ -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
 
@@ -641,22 +652,19 @@ void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
641
652
  }
642
653
 
643
654
  /*
644
- * call-seq:
645
- * Message.new(kwargs) => new_message
655
+ * ruby-doc: AbstractMessage#initialize
646
656
  *
647
657
  * Creates a new instance of the given message class. Keyword arguments may be
648
658
  * provided with keywords corresponding to field names.
649
659
  *
650
- * Note that no literal Message class exists. Only concrete classes per message
651
- * type exist, as provided by the #msgclass method on Descriptors after they
652
- * have been added to a pool. The method definitions described here on the
653
- * Message class are provided on each concrete message class.
660
+ * @param kwargs the list of field keys and values.
654
661
  */
655
662
  static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
656
663
  Message* self = ruby_to_Message(_self);
657
664
  VALUE arena_rb = Arena_new();
658
665
  upb_Arena* arena = Arena_get(arena_rb);
659
- upb_Message* msg = upb_Message_New(self->msgdef, arena);
666
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
667
+ upb_Message* msg = upb_Message_New(t, arena);
660
668
 
661
669
  Message_InitPtr(_self, msg, arena_rb);
662
670
 
@@ -671,56 +679,32 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
671
679
  }
672
680
 
673
681
  /*
674
- * call-seq:
675
- * Message.dup => new_message
682
+ * ruby-doc: AbstractMessage#dup
676
683
  *
677
684
  * Performs a shallow copy of this message and returns the new copy.
685
+ *
686
+ * @return [AbstractMessage]
678
687
  */
679
688
  static VALUE Message_dup(VALUE _self) {
680
689
  Message* self = ruby_to_Message(_self);
681
690
  VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
682
691
  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);
692
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
693
+ upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
688
694
  Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
689
695
  return new_msg;
690
696
  }
691
697
 
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
698
  /*
717
- * call-seq:
718
- * Message.==(other) => boolean
699
+ * ruby-doc: AbstractMessage#==
719
700
  *
720
701
  * Performs a deep comparison of this message with another. Messages are equal
721
702
  * if they have the same type and if each field is equal according to the :==
722
703
  * method's semantics (a more efficient comparison may actually be done if the
723
704
  * field is of a primitive type).
705
+ *
706
+ * @param other [AbstractMessage]
707
+ * @return [Boolean]
724
708
  */
725
709
  static VALUE Message_eq(VALUE _self, VALUE _other) {
726
710
  if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse;
@@ -729,35 +713,31 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
729
713
  Message* other = ruby_to_Message(_other);
730
714
  assert(self->msgdef == other->msgdef);
731
715
 
732
- return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
716
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
717
+ const int options = 0;
718
+ return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue
719
+ : Qfalse;
733
720
  }
734
721
 
735
722
  uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
736
723
  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;
724
+ upb_Status status;
725
+ upb_Status_Clear(&status);
726
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
727
+ if (upb_Status_IsOk(&status)) {
728
+ return return_value;
750
729
  } else {
751
- upb_Arena_Free(arena);
752
- rb_raise(cParseError, "Error calculating hash");
730
+ rb_raise(cParseError, "Message_Hash(): %s",
731
+ upb_Status_ErrorMessage(&status));
753
732
  }
754
733
  }
755
734
 
756
735
  /*
757
- * call-seq:
758
- * Message.hash => hash_value
736
+ * ruby-doc: AbstractMessage#hash
759
737
  *
760
738
  * Returns a hash value that represents this message's field values.
739
+ *
740
+ * @return [Integer]
761
741
  */
762
742
  static VALUE Message_hash(VALUE _self) {
763
743
  Message* self = ruby_to_Message(_self);
@@ -768,12 +748,13 @@ static VALUE Message_hash(VALUE _self) {
768
748
  }
769
749
 
770
750
  /*
771
- * call-seq:
772
- * Message.inspect => string
751
+ * ruby-doc: AbstractMessage#inspect
773
752
  *
774
753
  * Returns a human-readable string representing this message. It will be
775
754
  * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
776
755
  * field's value is represented according to its own #inspect method.
756
+ *
757
+ * @return [String]
777
758
  */
778
759
  static VALUE Message_inspect(VALUE _self) {
779
760
  Message* self = ruby_to_Message(_self);
@@ -806,57 +787,34 @@ static VALUE Message_CreateHash(const upb_Message* msg,
806
787
  if (!msg) return Qnil;
807
788
 
808
789
  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
- }
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;
832
794
 
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)) {
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]"
836
799
  continue;
837
800
  }
838
801
 
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.
802
+ TypeInfo type_info = TypeInfo_get(field);
803
+ VALUE msg_value;
843
804
 
844
805
  if (upb_FieldDef_IsMap(field)) {
845
806
  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
846
807
  const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
847
808
  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
848
809
  upb_CType key_type = upb_FieldDef_CType(key_f);
849
- 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));
850
811
  } 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);
812
+ msg_value = RepeatedField_CreateArray(val.array_val, type_info);
856
813
  } else {
857
- msg_value = Scalar_CreateHash(msgval, type_info);
814
+ msg_value = Scalar_CreateHash(val, type_info);
858
815
  }
859
816
 
817
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
860
818
  rb_hash_aset(hash, msg_key, msg_value);
861
819
  }
862
820
 
@@ -872,10 +830,11 @@ VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
872
830
  }
873
831
 
874
832
  /*
875
- * call-seq:
876
- * Message.to_h => {}
833
+ * ruby-doc: AbstractMessage#to_h
877
834
  *
878
835
  * Returns the message as a Ruby Hash object, with keys as symbols.
836
+ *
837
+ * @return [Hash]
879
838
  */
880
839
  static VALUE Message_to_h(VALUE _self) {
881
840
  Message* self = ruby_to_Message(_self);
@@ -883,27 +842,56 @@ static VALUE Message_to_h(VALUE _self) {
883
842
  }
884
843
 
885
844
  /*
886
- * call-seq:
887
- * Message.freeze => self
845
+ * ruby-doc: AbstractMessage#frozen?
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
+ * @return [Boolean]
852
+ */
853
+ VALUE Message_frozen(VALUE _self) {
854
+ Message* self = ruby_to_Message(_self);
855
+ if (!upb_Message_IsFrozen(self->msg)) {
856
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
857
+ return Qfalse;
858
+ }
859
+
860
+ // Lazily freeze the Ruby wrapper.
861
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
862
+ return Qtrue;
863
+ }
864
+
865
+ /*
866
+ * ruby-doc: AbstractMessage#freeze
867
+ *
868
+ * Freezes the message object. We have to intercept this so we can freeze the
869
+ * underlying representation, not just the Ruby wrapper.
888
870
  *
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.
871
+ * @return [self]
891
872
  */
892
- static VALUE Message_freeze(VALUE _self) {
873
+ VALUE Message_freeze(VALUE _self) {
893
874
  Message* self = ruby_to_Message(_self);
894
- if (!RB_OBJ_FROZEN(_self)) {
895
- Arena_Pin(self->arena, _self);
896
- RB_OBJ_FREEZE(_self);
875
+ if (RB_OBJ_FROZEN(_self)) {
876
+ PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg));
877
+ return _self;
897
878
  }
879
+ if (!upb_Message_IsFrozen(self->msg)) {
880
+ upb_Message_Freeze(Message_GetMutable(_self, NULL),
881
+ upb_MessageDef_MiniTable(self->msgdef));
882
+ }
883
+ RB_OBJ_FREEZE(_self);
898
884
  return _self;
899
885
  }
900
886
 
901
887
  /*
902
- * call-seq:
903
- * Message.[](index) => value
888
+ * ruby-doc: AbstractMessage#[]
904
889
  *
905
890
  * Accesses a field's value by field name. The provided field name should be a
906
891
  * string.
892
+ *
893
+ * @param index [Integer]
894
+ * @return [Object]
907
895
  */
908
896
  static VALUE Message_index(VALUE _self, VALUE field_name) {
909
897
  Message* self = ruby_to_Message(_self);
@@ -920,11 +908,14 @@ static VALUE Message_index(VALUE _self, VALUE field_name) {
920
908
  }
921
909
 
922
910
  /*
923
- * call-seq:
924
- * Message.[]=(index, value)
911
+ * ruby-doc: AbstractMessage#[]=
925
912
  *
926
913
  * Sets a field's value by field name. The provided field name should be a
927
914
  * string.
915
+ *
916
+ * @param index [Integer]
917
+ * @param value [Object]
918
+ * @return [nil]
928
919
  */
929
920
  static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
930
921
  Message* self = ruby_to_Message(_self);
@@ -940,20 +931,22 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
940
931
  }
941
932
 
942
933
  val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
943
- upb_Message_Set(Message_GetMutable(_self, NULL), f, val, arena);
934
+ upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
944
935
 
945
936
  return Qnil;
946
937
  }
947
938
 
948
939
  /*
949
- * call-seq:
950
- * MessageClass.decode(data, options) => message
940
+ * ruby-doc: AbstractMessage.decode
951
941
  *
952
942
  * 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
943
+ * format) under the interpretation given by this message class's definition
954
944
  * and returns a message object with the corresponding field values.
955
- * @param options [Hash] options for the decoder
956
- * recursion_limit: set to maximum decoding depth for message (default is 64)
945
+ * @param data [String]
946
+ * @param options [Hash]
947
+ * @option recursion_limit [Integer] set to maximum decoding depth for message
948
+ * (default is 64)
949
+ * @return [AbstractMessage]
957
950
  */
958
951
  static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
959
952
  VALUE data = argv[0];
@@ -969,10 +962,11 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
969
962
  rb_raise(rb_eArgError, "Expected hash arguments.");
970
963
  }
971
964
 
972
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
965
+ VALUE depth =
966
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
973
967
 
974
968
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
975
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
969
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
976
970
  }
977
971
  }
978
972
 
@@ -980,40 +974,48 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
980
974
  rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
981
975
  }
982
976
 
977
+ return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options,
978
+ klass, /*freeze*/ false);
979
+ }
980
+
981
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
982
+ VALUE klass, bool freeze) {
983
983
  VALUE msg_rb = initialize_rb_class_with_no_args(klass);
984
984
  Message* msg = ruby_to_Message(msg_rb);
985
985
 
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
-
986
+ const upb_FileDef* file = upb_MessageDef_File(msg->msgdef);
987
+ const upb_ExtensionRegistry* extreg =
988
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
989
+ upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
990
+ upb_MessageDef_MiniTable(msg->msgdef),
991
+ extreg, options, Arena_get(msg->arena));
990
992
  if (status != kUpb_DecodeStatus_Ok) {
991
993
  rb_raise(cParseError, "Error occurred during parsing");
992
994
  }
993
-
995
+ if (freeze) {
996
+ Message_freeze(msg_rb);
997
+ }
994
998
  return msg_rb;
995
999
  }
996
1000
 
997
1001
  /*
998
- * call-seq:
999
- * MessageClass.decode_json(data, options = {}) => message
1002
+ * ruby-doc: AbstractMessage.decode_json
1000
1003
  *
1001
1004
  * Decodes the given data (as a string containing bytes in protocol buffers wire
1002
1005
  * format) under the interpretration given by this message class's definition
1003
1006
  * and returns a message object with the corresponding field values.
1004
1007
  *
1005
- * @param options [Hash] options for the decoder
1006
- * ignore_unknown_fields: set true to ignore unknown fields (default is to
1007
- * raise an error)
1008
+ * @param data [String]
1009
+ * @param options [Hash]
1010
+ * @option ignore_unknown_fields [Boolean] set true to ignore unknown fields
1011
+ * (default is to raise an error)
1012
+ * @return [AbstractMessage]
1008
1013
  */
1009
1014
  static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1010
1015
  VALUE data = argv[0];
1011
1016
  int options = 0;
1012
1017
  upb_Status status;
1013
1018
 
1014
- // TODO(haberman): use this message's pool instead.
1015
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1016
-
1017
1019
  if (argc < 1 || argc > 2) {
1018
1020
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1019
1021
  }
@@ -1034,7 +1036,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1034
1036
  rb_raise(rb_eArgError, "Expected string for JSON data.");
1035
1037
  }
1036
1038
 
1037
- // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
1039
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1038
1040
  // convert, because string handlers pass data directly to message string
1039
1041
  // fields.
1040
1042
 
@@ -1047,29 +1049,40 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1047
1049
  }
1048
1050
 
1049
1051
  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));
1052
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1053
+
1054
+ int result = upb_JsonDecodeDetectingNonconformance(
1055
+ RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
1056
+ msg->msgdef, pool, options, Arena_get(msg->arena), &status);
1057
+
1058
+ switch (result) {
1059
+ case kUpb_JsonDecodeResult_Ok:
1060
+ break;
1061
+ case kUpb_JsonDecodeResult_Error:
1062
+ rb_raise(cParseError, "Error occurred during parsing: %s",
1063
+ upb_Status_ErrorMessage(&status));
1064
+ break;
1055
1065
  }
1056
1066
 
1057
1067
  return msg_rb;
1058
1068
  }
1059
1069
 
1060
1070
  /*
1061
- * call-seq:
1062
- * MessageClass.encode(msg, options) => bytes
1071
+ * ruby-doc: AbstractMessage.encode
1063
1072
  *
1064
1073
  * Encodes the given message object to its serialized form in protocol buffers
1065
1074
  * wire format.
1066
- * @param options [Hash] options for the encoder
1067
- * recursion_limit: set to maximum encoding depth for message (default is 64)
1075
+ *
1076
+ * @param msg [AbstractMessage]
1077
+ * @param options [Hash]
1078
+ * @option recursion_limit [Integer] set to maximum encoding depth for message
1079
+ * (default is 64)
1080
+ * @return [String]
1068
1081
  */
1069
1082
  static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1070
1083
  Message* msg = ruby_to_Message(argv[0]);
1071
1084
  int options = 0;
1072
- const char* data;
1085
+ char* data;
1073
1086
  size_t size;
1074
1087
 
1075
1088
  if (CLASS_OF(argv[0]) != klass) {
@@ -1085,19 +1098,21 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1085
1098
  if (TYPE(hash_args) != T_HASH) {
1086
1099
  rb_raise(rb_eArgError, "Expected hash arguments.");
1087
1100
  }
1088
- VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1101
+ VALUE depth =
1102
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1089
1103
 
1090
1104
  if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1091
- options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));
1105
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1092
1106
  }
1093
1107
  }
1094
1108
 
1095
- upb_Arena *arena = upb_Arena_New();
1109
+ upb_Arena* arena = upb_Arena_New();
1096
1110
 
1097
- data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef),
1098
- options, arena, &size);
1111
+ upb_EncodeStatus status =
1112
+ upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
1113
+ arena, &data, &size);
1099
1114
 
1100
- if (data) {
1115
+ if (status == kUpb_EncodeStatus_Ok) {
1101
1116
  VALUE ret = rb_str_new(data, size);
1102
1117
  rb_enc_associate(ret, rb_ascii8bit_encoding());
1103
1118
  upb_Arena_Free(arena);
@@ -1109,14 +1124,17 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1109
1124
  }
1110
1125
 
1111
1126
  /*
1112
- * call-seq:
1113
- * MessageClass.encode_json(msg, options = {}) => json_string
1127
+ * ruby-doc: AbstractMessage.encode_json
1114
1128
  *
1115
1129
  * Encodes the given message object into its serialized JSON representation.
1116
- * @param options [Hash] options for the decoder
1117
- * preserve_proto_fieldnames: set true to use original fieldnames (default is
1118
- * to camelCase) emit_defaults: set true to emit 0/false values (default is to
1119
- * omit them)
1130
+ *
1131
+ * @param msg [AbstractMessage]
1132
+ * @param options [Hash]
1133
+ * @option preserve_proto_fieldnames [Boolean] set true to use original
1134
+ * fieldnames (default is to camelCase)
1135
+ * @option emit_defaults [Boolean] set true to emit 0/false values (default is
1136
+ * to omit them)
1137
+ * @return [String]
1120
1138
  */
1121
1139
  static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1122
1140
  Message* msg = ruby_to_Message(argv[0]);
@@ -1125,9 +1143,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1125
1143
  size_t size;
1126
1144
  upb_Status status;
1127
1145
 
1128
- // TODO(haberman): use this message's pool instead.
1129
- const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
1130
-
1131
1146
  if (argc < 1 || argc > 2) {
1132
1147
  rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1133
1148
  }
@@ -1135,7 +1150,8 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1135
1150
  if (argc == 2) {
1136
1151
  VALUE hash_args = argv[1];
1137
1152
  if (TYPE(hash_args) != T_HASH) {
1138
- if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, rb_str_new2("to_h")))) {
1153
+ if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1,
1154
+ rb_str_new2("to_h")))) {
1139
1155
  hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0);
1140
1156
  } else {
1141
1157
  rb_raise(rb_eArgError, "Expected hash arguments.");
@@ -1152,11 +1168,18 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1152
1168
  Qfalse))) {
1153
1169
  options |= upb_JsonEncode_EmitDefaults;
1154
1170
  }
1171
+
1172
+ if (RTEST(rb_hash_lookup2(hash_args,
1173
+ ID2SYM(rb_intern("format_enums_as_integers")),
1174
+ Qfalse))) {
1175
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
1176
+ }
1155
1177
  }
1156
1178
 
1157
1179
  upb_Status_Clear(&status);
1158
- size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
1159
- sizeof(buf), &status);
1180
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1181
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1182
+ &status);
1160
1183
 
1161
1184
  if (!upb_Status_IsOk(&status)) {
1162
1185
  rb_raise(cParseError, "Error occurred during encoding: %s",
@@ -1166,7 +1189,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1166
1189
  VALUE ret;
1167
1190
  if (size >= sizeof(buf)) {
1168
1191
  char* buf2 = malloc(size + 1);
1169
- upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
1192
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1170
1193
  &status);
1171
1194
  ret = rb_str_new(buf2, size);
1172
1195
  free(buf2);
@@ -1179,11 +1202,12 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1179
1202
  }
1180
1203
 
1181
1204
  /*
1182
- * call-seq:
1183
- * Message.descriptor => descriptor
1205
+ * ruby-doc: AbstractMessage.descriptor
1184
1206
  *
1185
1207
  * Class method that returns the Descriptor instance corresponding to this
1186
1208
  * message class's type.
1209
+ *
1210
+ * @return [Descriptor]
1187
1211
  */
1188
1212
  static VALUE Message_descriptor(VALUE klass) {
1189
1213
  return rb_ivar_get(klass, descriptor_instancevar_interned);
@@ -1201,45 +1225,31 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
1201
1225
  klass = rb_define_class_id(
1202
1226
  // Docs say this parameter is ignored. User will assign return value to
1203
1227
  // their own toplevel constant class name.
1204
- rb_intern("Message"), rb_cObject);
1228
+ rb_intern("Message"), cAbstractMessage);
1205
1229
  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
1230
  return klass;
1235
1231
  }
1236
1232
 
1233
+ /* ruby-doc: Enum
1234
+ *
1235
+ * There isn't really a concrete `Enum` module generated by Protobuf. Instead,
1236
+ * you can use this documentation as an indicator of methods that are defined on
1237
+ * each `Enum` module that is generated. E.g. if you have:
1238
+ *
1239
+ * enum my_enum_type
1240
+ *
1241
+ * in your Proto file and generate Ruby code, a module
1242
+ * called `MyEnumType` will be generated with the following methods available.
1243
+ */
1244
+
1237
1245
  /*
1238
- * call-seq:
1239
- * Enum.lookup(number) => name
1246
+ * ruby-doc: Enum.lookup
1240
1247
  *
1241
1248
  * This module method, provided on each generated enum module, looks up an enum
1242
1249
  * value by number and returns its name as a Ruby symbol, or nil if not found.
1250
+ *
1251
+ * @param number [Integer]
1252
+ * @return [String]
1243
1253
  */
1244
1254
  static VALUE enum_lookup(VALUE self, VALUE number) {
1245
1255
  int32_t num = NUM2INT(number);
@@ -1254,11 +1264,13 @@ static VALUE enum_lookup(VALUE self, VALUE number) {
1254
1264
  }
1255
1265
 
1256
1266
  /*
1257
- * call-seq:
1258
- * Enum.resolve(name) => number
1267
+ * ruby-doc: Enum.resolve
1259
1268
  *
1260
1269
  * This module method, provided on each generated enum module, looks up an enum
1261
1270
  * value by name (as a Ruby symbol) and returns its name, or nil if not found.
1271
+ *
1272
+ * @param name [String]
1273
+ * @return [Integer]
1262
1274
  */
1263
1275
  static VALUE enum_resolve(VALUE self, VALUE sym) {
1264
1276
  const char* name = rb_id2name(SYM2ID(sym));
@@ -1273,11 +1285,13 @@ static VALUE enum_resolve(VALUE self, VALUE sym) {
1273
1285
  }
1274
1286
 
1275
1287
  /*
1276
- * call-seq:
1277
- * Enum.descriptor
1288
+ * ruby-doc: Enum.descriptor
1278
1289
  *
1279
1290
  * This module method, provided on each generated enum module, returns the
1280
- * EnumDescriptor corresponding to this enum type.
1291
+ * {EnumDescriptor} corresponding to this enum type.
1292
+ *
1293
+ * @return [EnumDescriptor]
1294
+ *
1281
1295
  */
1282
1296
  static VALUE enum_descriptor(VALUE self) {
1283
1297
  return rb_ivar_get(self, descriptor_instancevar_interned);
@@ -1290,15 +1304,22 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1290
1304
  int n = upb_EnumDef_ValueCount(e);
1291
1305
  for (int i = 0; i < n; i++) {
1292
1306
  const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
1293
- const char* name = upb_EnumValueDef_Name(ev);
1307
+ upb_Arena* arena = upb_Arena_New();
1308
+ const char* src_name = upb_EnumValueDef_Name(ev);
1309
+ char* name = upb_strdup2(src_name, strlen(src_name), arena);
1294
1310
  int32_t value = upb_EnumValueDef_Number(ev);
1295
1311
  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);
1312
+ if (name[0] >= 'a' && name[0] <= 'z') {
1313
+ name[0] -= 32; // auto capitalize
1314
+ } else {
1315
+ rb_warn(
1316
+ "Enum value '%s' does not start with an uppercase letter "
1317
+ "as is required for Ruby constants.",
1318
+ name);
1319
+ }
1300
1320
  }
1301
1321
  rb_define_const(mod, name, INT2NUM(value));
1322
+ upb_Arena_Free(arena);
1302
1323
  }
1303
1324
 
1304
1325
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
@@ -1309,7 +1330,7 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1309
1330
  return mod;
1310
1331
  }
1311
1332
 
1312
- // Internal only; used by Google::Protobuf.deep_copy.
1333
+ // Internal to the library; used by Google::Protobuf.deep_copy.
1313
1334
  upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1314
1335
  upb_Arena* arena) {
1315
1336
  // Serialize and parse.
@@ -1317,11 +1338,16 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1317
1338
  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1318
1339
  size_t size;
1319
1340
 
1320
- char* data = upb_Encode(msg, layout, 0, tmp_arena, &size);
1321
- upb_Message* new_msg = upb_Message_New(m, arena);
1341
+ upb_Message* new_msg = upb_Message_New(layout, arena);
1342
+ char* data;
1322
1343
 
1323
- if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
1324
- kUpb_DecodeStatus_Ok) {
1344
+ const upb_FileDef* file = upb_MessageDef_File(m);
1345
+ const upb_ExtensionRegistry* extreg =
1346
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1347
+ if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1348
+ kUpb_EncodeStatus_Ok ||
1349
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1350
+ kUpb_DecodeStatus_Ok) {
1325
1351
  upb_Arena_Free(tmp_arena);
1326
1352
  rb_raise(cParseError, "Error occurred copying proto");
1327
1353
  }
@@ -1348,7 +1374,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1348
1374
  switch (upb_MessageDef_WellKnownType(m)) {
1349
1375
  case kUpb_WellKnown_Timestamp: {
1350
1376
  // Time -> Google::Protobuf::Timestamp
1351
- upb_Message* msg = upb_Message_New(m, arena);
1377
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1378
+ upb_Message* msg = upb_Message_New(t, arena);
1352
1379
  upb_MessageValue sec, nsec;
1353
1380
  struct timespec time;
1354
1381
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
@@ -1359,13 +1386,14 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1359
1386
  time = rb_time_timespec(value);
1360
1387
  sec.int64_val = time.tv_sec;
1361
1388
  nsec.int32_val = time.tv_nsec;
1362
- upb_Message_Set(msg, sec_f, sec, arena);
1363
- upb_Message_Set(msg, nsec_f, nsec, arena);
1389
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1390
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1364
1391
  return msg;
1365
1392
  }
1366
1393
  case kUpb_WellKnown_Duration: {
1367
1394
  // Numeric -> Google::Protobuf::Duration
1368
- upb_Message* msg = upb_Message_New(m, arena);
1395
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1396
+ upb_Message* msg = upb_Message_New(t, arena);
1369
1397
  upb_MessageValue sec, nsec;
1370
1398
  const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1371
1399
  const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
@@ -1374,8 +1402,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1374
1402
 
1375
1403
  sec.int64_val = NUM2LL(value);
1376
1404
  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);
1405
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1406
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1379
1407
  return msg;
1380
1408
  }
1381
1409
  default:
@@ -1392,11 +1420,43 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1392
1420
  return self->msg;
1393
1421
  }
1394
1422
 
1423
+ static void Message_define_class(VALUE klass) {
1424
+ rb_define_alloc_func(klass, Message_alloc);
1425
+
1426
+ rb_require("google/protobuf/message_exts");
1427
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
1428
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1429
+ -1);
1430
+ rb_define_method(klass, "initialize", Message_initialize, -1);
1431
+ rb_define_method(klass, "dup", Message_dup, 0);
1432
+ // Also define #clone so that we don't inherit Object#clone.
1433
+ rb_define_method(klass, "clone", Message_dup, 0);
1434
+ rb_define_method(klass, "==", Message_eq, 1);
1435
+ rb_define_method(klass, "eql?", Message_eq, 1);
1436
+ rb_define_method(klass, "freeze", Message_freeze, 0);
1437
+ rb_define_method(klass, "frozen?", Message_frozen, 0);
1438
+ rb_define_method(klass, "hash", Message_hash, 0);
1439
+ rb_define_method(klass, "to_h", Message_to_h, 0);
1440
+ rb_define_method(klass, "inspect", Message_inspect, 0);
1441
+ rb_define_method(klass, "to_s", Message_inspect, 0);
1442
+ rb_define_method(klass, "[]", Message_index, 1);
1443
+ rb_define_method(klass, "[]=", Message_index_set, 2);
1444
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
1445
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
1446
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1447
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1448
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1449
+ }
1450
+
1395
1451
  void Message_register(VALUE protobuf) {
1396
1452
  cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
1453
+ cAbstractMessage =
1454
+ rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
1455
+ Message_define_class(cAbstractMessage);
1456
+ rb_gc_register_address(&cAbstractMessage);
1397
1457
 
1398
1458
  // Ruby-interned string: "descriptor". We use this identifier to store an
1399
1459
  // instance variable on message classes we create in order to link them back
1400
1460
  // to their descriptors.
1401
- descriptor_instancevar_interned = rb_intern("descriptor");
1461
+ descriptor_instancevar_interned = rb_intern("@descriptor");
1402
1462
  }