google-protobuf 3.14.0 → 4.26.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +317 -0
  4. data/ext/google/protobuf_c/convert.h +50 -0
  5. data/ext/google/protobuf_c/defs.c +759 -1709
  6. data/ext/google/protobuf_c/defs.h +82 -0
  7. data/ext/google/protobuf_c/extconf.rb +15 -8
  8. data/ext/google/protobuf_c/glue.c +56 -0
  9. data/ext/google/protobuf_c/map.c +328 -485
  10. data/ext/google/protobuf_c/map.h +44 -0
  11. data/ext/google/protobuf_c/message.c +1061 -530
  12. data/ext/google/protobuf_c/message.h +86 -0
  13. data/ext/google/protobuf_c/protobuf.c +314 -94
  14. data/ext/google/protobuf_c/protobuf.h +66 -621
  15. data/ext/google/protobuf_c/repeated_field.c +314 -353
  16. data/ext/google/protobuf_c/repeated_field.h +41 -0
  17. data/ext/google/protobuf_c/ruby-upb.c +15407 -0
  18. data/ext/google/protobuf_c/ruby-upb.h +13966 -0
  19. data/ext/google/protobuf_c/shared_convert.c +66 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +67 -0
  22. data/ext/google/protobuf_c/shared_message.h +25 -0
  23. data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +22 -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 +22 -0
  26. data/ext/google/protobuf_c/wrap_memcpy.c +7 -29
  27. data/lib/google/protobuf/any_pb.rb +6 -8
  28. data/lib/google/protobuf/api_pb.rb +7 -26
  29. data/lib/google/protobuf/descriptor_pb.rb +65 -0
  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 +164 -0
  33. data/lib/google/protobuf/ffi/descriptor_pool.rb +75 -0
  34. data/lib/google/protobuf/ffi/enum_descriptor.rb +171 -0
  35. data/lib/google/protobuf/ffi/ffi.rb +215 -0
  36. data/lib/google/protobuf/ffi/field_descriptor.rb +328 -0
  37. data/lib/google/protobuf/ffi/file_descriptor.rb +47 -0
  38. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  39. data/lib/google/protobuf/ffi/internal/convert.rb +289 -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 +409 -0
  43. data/lib/google/protobuf/ffi/message.rb +659 -0
  44. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  45. data/lib/google/protobuf/ffi/oneof_descriptor.rb +95 -0
  46. data/lib/google/protobuf/ffi/repeated_field.rb +385 -0
  47. data/lib/google/protobuf/field_mask_pb.rb +6 -7
  48. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  49. data/lib/google/protobuf/message_exts.rb +10 -28
  50. data/lib/google/protobuf/plugin_pb.rb +25 -0
  51. data/lib/google/protobuf/repeated_field.rb +19 -30
  52. data/lib/google/protobuf/source_context_pb.rb +6 -7
  53. data/lib/google/protobuf/struct_pb.rb +6 -23
  54. data/lib/google/protobuf/timestamp_pb.rb +6 -8
  55. data/lib/google/protobuf/type_pb.rb +7 -71
  56. data/lib/google/protobuf/well_known_types.rb +17 -36
  57. data/lib/google/protobuf/wrappers_pb.rb +6 -31
  58. data/lib/google/protobuf.rb +32 -118
  59. data/lib/google/protobuf_ffi.rb +49 -0
  60. data/lib/google/protobuf_native.rb +19 -0
  61. data/lib/google/tasks/ffi.rake +100 -0
  62. metadata +88 -37
  63. data/ext/google/protobuf_c/encode_decode.c +0 -1795
  64. data/ext/google/protobuf_c/storage.c +0 -1198
  65. data/ext/google/protobuf_c/upb.c +0 -13817
  66. data/ext/google/protobuf_c/upb.h +0 -6777
  67. data/tests/basic.rb +0 -543
  68. data/tests/generated_code_test.rb +0 -23
  69. data/tests/stress.rb +0 -38
@@ -1,76 +1,71 @@
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
7
+
8
+ #include "message.h"
30
9
 
10
+ #include "convert.h"
11
+ #include "defs.h"
12
+ #include "map.h"
31
13
  #include "protobuf.h"
14
+ #include "repeated_field.h"
15
+ #include "shared_message.h"
32
16
 
33
- // -----------------------------------------------------------------------------
34
- // Class/module creation from msgdefs and enumdefs, respectively.
35
- // -----------------------------------------------------------------------------
17
+ static VALUE cParseError = Qnil;
18
+ static VALUE cAbstractMessage = Qnil;
19
+ static ID descriptor_instancevar_interned;
36
20
 
37
- void* Message_data(void* msg) {
38
- return ((uint8_t *)msg) + sizeof(MessageHeader);
21
+ static VALUE initialize_rb_class_with_no_args(VALUE klass) {
22
+ return rb_funcall(klass, rb_intern("new"), 0);
39
23
  }
40
24
 
41
- void Message_mark(void* _self) {
42
- MessageHeader* self = (MessageHeader *)_self;
43
- layout_mark(self->descriptor->layout, Message_data(self));
25
+ VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
26
+ return rb_ivar_get(klass, descriptor_instancevar_interned);
44
27
  }
45
28
 
46
- void Message_free(void* self) {
47
- stringsink* unknown = ((MessageHeader *)self)->unknown_fields;
48
- if (unknown != NULL) {
49
- stringsink_uninit(unknown);
50
- free(unknown);
51
- }
52
- xfree(self);
29
+ // -----------------------------------------------------------------------------
30
+ // Class/module creation from msgdefs and enumdefs, respectively.
31
+ // -----------------------------------------------------------------------------
32
+
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.
36
+ VALUE arena;
37
+ const upb_Message* msg; // Can get as mutable when non-frozen.
38
+ const upb_MessageDef*
39
+ msgdef; // kept alive by self.class.descriptor reference.
40
+ } Message;
41
+
42
+ static void Message_mark(void* _self) {
43
+ Message* self = (Message*)_self;
44
+ rb_gc_mark(self->arena);
53
45
  }
54
46
 
55
- rb_data_type_t Message_type = {
56
- "Message",
57
- { Message_mark, Message_free, NULL },
47
+ static size_t Message_memsize(const void* _self) { return sizeof(Message); }
48
+
49
+ static rb_data_type_t Message_type = {
50
+ "Google::Protobuf::Message",
51
+ {Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
52
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
58
53
  };
59
54
 
60
- VALUE Message_alloc(VALUE klass) {
55
+ static Message* ruby_to_Message(VALUE msg_rb) {
56
+ Message* msg;
57
+ TypedData_Get_Struct(msg_rb, Message, &Message_type, msg);
58
+ return msg;
59
+ }
60
+
61
+ static VALUE Message_alloc(VALUE klass) {
61
62
  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
62
- Descriptor* desc = ruby_to_Descriptor(descriptor);
63
- MessageHeader* msg;
63
+ Message* msg = ALLOC(Message);
64
64
  VALUE ret;
65
65
 
66
- if (desc->layout == NULL) {
67
- create_layout(desc);
68
- }
69
-
70
- msg = (void*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
71
- msg->descriptor = desc;
72
- msg->unknown_fields = NULL;
73
- memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
66
+ msg->msgdef = Descriptor_GetMsgDef(descriptor);
67
+ msg->arena = Qnil;
68
+ msg->msg = NULL;
74
69
 
75
70
  ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
76
71
  rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
@@ -78,24 +73,96 @@ VALUE Message_alloc(VALUE klass) {
78
73
  return ret;
79
74
  }
80
75
 
81
- static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
82
- uint32_t oneof_case;
83
- const upb_fielddef* f;
76
+ const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
77
+ Message* msg = ruby_to_Message(msg_rb);
78
+ if (m) *m = msg->msgdef;
79
+ return msg->msg;
80
+ }
81
+
82
+ upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
83
+ rb_check_frozen(msg_rb);
84
+ return (upb_Message*)Message_Get(msg_rb, m);
85
+ }
86
+
87
+ void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
88
+ Message* self = ruby_to_Message(self_);
89
+ self->msg = msg;
90
+ RB_OBJ_WRITE(self_, &self->arena, arena);
91
+ VALUE stored = ObjectCache_TryAdd(msg, self_);
92
+ (void)stored;
93
+ PBRUBY_ASSERT(stored == self_);
94
+ }
95
+
96
+ VALUE Message_GetArena(VALUE msg_rb) {
97
+ Message* msg = ruby_to_Message(msg_rb);
98
+ return msg->arena;
99
+ }
100
+
101
+ void Message_CheckClass(VALUE klass) {
102
+ if (rb_get_alloc_func(klass) != &Message_alloc) {
103
+ rb_raise(rb_eArgError,
104
+ "Message class was not returned by the DescriptorPool.");
105
+ }
106
+ }
107
+
108
+ VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
109
+ VALUE arena) {
110
+ if (msg == NULL) return Qnil;
84
111
 
85
- oneof_case =
86
- slot_read_oneof_case(self->descriptor->layout, Message_data(self), o);
112
+ VALUE val = ObjectCache_Get(msg);
87
113
 
88
- if (oneof_case == ONEOF_CASE_NONE) {
89
- return NULL;
114
+ if (val == Qnil) {
115
+ VALUE klass = Descriptor_DefToClass(m);
116
+ val = Message_alloc(klass);
117
+ Message_InitPtr(val, msg, arena);
90
118
  }
91
119
 
92
- // oneof_case is a field index, so find that field.
93
- f = upb_oneofdef_itof(o, oneof_case);
94
- assert(f != NULL);
120
+ return val;
121
+ }
122
+
123
+ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
124
+ const upb_MessageDef* m) {
125
+ bool first = true;
126
+ int n = upb_MessageDef_FieldCount(m);
127
+ VALUE klass = Descriptor_DefToClass(m);
128
+ StringBuilder_Printf(b, "<%s: ", rb_class2name(klass));
129
+
130
+ for (int i = 0; i < n; i++) {
131
+ const upb_FieldDef* field = upb_MessageDef_Field(m, i);
132
+
133
+ if (upb_FieldDef_HasPresence(field) &&
134
+ !upb_Message_HasFieldByDef(msg, field)) {
135
+ continue;
136
+ }
137
+
138
+ if (!first) {
139
+ StringBuilder_Printf(b, ", ");
140
+ } else {
141
+ first = false;
142
+ }
143
+
144
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field);
145
+
146
+ StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field));
147
+
148
+ if (upb_FieldDef_IsMap(field)) {
149
+ const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
150
+ const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
151
+ const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
152
+ TypeInfo val_info = TypeInfo_get(val_f);
153
+ Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info);
154
+ } else if (upb_FieldDef_IsRepeated(field)) {
155
+ RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field));
156
+ } else {
157
+ StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field));
158
+ }
159
+ }
95
160
 
96
- return f;
161
+ StringBuilder_Printf(b, ">");
97
162
  }
98
163
 
164
+ // Helper functions for #method_missing ////////////////////////////////////////
165
+
99
166
  enum {
100
167
  METHOD_UNKNOWN = 0,
101
168
  METHOD_GETTER = 1,
@@ -108,153 +175,217 @@ enum {
108
175
  };
109
176
 
110
177
  // Check if the field is a well known wrapper type
111
- bool is_wrapper_type_field(const upb_fielddef* field) {
112
- const upb_msgdef *m;
113
- if (upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
114
- return false;
115
- }
116
- m = upb_fielddef_msgsubdef(field);
117
- switch (upb_msgdef_wellknowntype(m)) {
118
- case UPB_WELLKNOWN_DOUBLEVALUE:
119
- case UPB_WELLKNOWN_FLOATVALUE:
120
- case UPB_WELLKNOWN_INT64VALUE:
121
- case UPB_WELLKNOWN_UINT64VALUE:
122
- case UPB_WELLKNOWN_INT32VALUE:
123
- case UPB_WELLKNOWN_UINT32VALUE:
124
- case UPB_WELLKNOWN_STRINGVALUE:
125
- case UPB_WELLKNOWN_BYTESVALUE:
126
- case UPB_WELLKNOWN_BOOLVALUE:
178
+ static bool IsWrapper(const upb_MessageDef* m) {
179
+ if (!m) return false;
180
+ switch (upb_MessageDef_WellKnownType(m)) {
181
+ case kUpb_WellKnown_DoubleValue:
182
+ case kUpb_WellKnown_FloatValue:
183
+ case kUpb_WellKnown_Int64Value:
184
+ case kUpb_WellKnown_UInt64Value:
185
+ case kUpb_WellKnown_Int32Value:
186
+ case kUpb_WellKnown_UInt32Value:
187
+ case kUpb_WellKnown_StringValue:
188
+ case kUpb_WellKnown_BytesValue:
189
+ case kUpb_WellKnown_BoolValue:
127
190
  return true;
128
191
  default:
129
192
  return false;
130
193
  }
131
194
  }
132
195
 
133
- // Get a new Ruby wrapper type and set the initial value
134
- VALUE ruby_wrapper_type(VALUE type_class, VALUE value) {
135
- if (value != Qnil) {
136
- VALUE hash = rb_hash_new();
137
- rb_hash_aset(hash, rb_str_new2("value"), value);
138
- {
139
- VALUE args[1] = {hash};
140
- return rb_class_new_instance(1, args, type_class);
141
- }
196
+ static bool IsFieldWrapper(const upb_FieldDef* f) {
197
+ return IsWrapper(upb_FieldDef_MessageSubDef(f));
198
+ }
199
+
200
+ static bool Match(const upb_MessageDef* m, const char* name,
201
+ const upb_FieldDef** f, const upb_OneofDef** o,
202
+ const char* prefix, const char* suffix) {
203
+ size_t sp = strlen(prefix);
204
+ size_t ss = strlen(suffix);
205
+ size_t sn = strlen(name);
206
+
207
+ if (sn <= sp + ss) return false;
208
+
209
+ if (memcmp(name, prefix, sp) != 0 ||
210
+ memcmp(name + sn - ss, suffix, ss) != 0) {
211
+ return false;
142
212
  }
143
- return Qnil;
213
+
214
+ return upb_MessageDef_FindByNameWithSize(m, name + sp, sn - sp - ss, f, o);
144
215
  }
145
216
 
146
- static int extract_method_call(VALUE method_name, MessageHeader* self,
147
- const upb_fielddef **f, const upb_oneofdef **o) {
148
- VALUE method_str;
149
- char* name;
150
- size_t name_len;
151
- int accessor_type;
152
- const upb_oneofdef* test_o;
153
- const upb_fielddef* test_f;
154
- bool has_field;
217
+ static int extract_method_call(VALUE method_name, Message* self,
218
+ const upb_FieldDef** f, const upb_OneofDef** o) {
219
+ const upb_MessageDef* m = self->msgdef;
220
+ const char* name;
155
221
 
156
222
  Check_Type(method_name, T_SYMBOL);
223
+ name = rb_id2name(SYM2ID(method_name));
224
+
225
+ if (Match(m, name, f, o, "", "")) return METHOD_GETTER;
226
+ if (Match(m, name, f, o, "", "=")) return METHOD_SETTER;
227
+ if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
228
+ if (Match(m, name, f, o, "has_", "?") &&
229
+ (*o || (*f && upb_FieldDef_HasPresence(*f)))) {
230
+ return METHOD_PRESENCE;
231
+ }
232
+ if (Match(m, name, f, o, "", "_as_value") && *f &&
233
+ !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
234
+ return METHOD_WRAPPER_GETTER;
235
+ }
236
+ if (Match(m, name, f, o, "", "_as_value=") && *f &&
237
+ !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
238
+ return METHOD_WRAPPER_SETTER;
239
+ }
240
+ if (Match(m, name, f, o, "", "_const") && *f &&
241
+ upb_FieldDef_CType(*f) == kUpb_CType_Enum) {
242
+ return METHOD_ENUM_GETTER;
243
+ }
157
244
 
158
- method_str = rb_id2str(SYM2ID(method_name));
159
- name = RSTRING_PTR(method_str);
160
- name_len = RSTRING_LEN(method_str);
161
-
162
- if (name[name_len - 1] == '=') {
163
- accessor_type = METHOD_SETTER;
164
- name_len--;
165
- // We want to ensure if the proto has something named clear_foo or has_foo?,
166
- // we don't strip the prefix.
167
- } else if (strncmp("clear_", name, 6) == 0 &&
168
- !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
169
- &test_f, &test_o)) {
170
- accessor_type = METHOD_CLEAR;
171
- name = name + 6;
172
- name_len = name_len - 6;
173
- } else if (strncmp("has_", name, 4) == 0 && name[name_len - 1] == '?' &&
174
- !upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
175
- &test_f, &test_o)) {
176
- accessor_type = METHOD_PRESENCE;
177
- name = name + 4;
178
- name_len = name_len - 5;
179
- } else {
180
- accessor_type = METHOD_GETTER;
181
- }
182
-
183
- has_field = upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len,
184
- &test_f, &test_o);
185
-
186
- // Look for wrapper type accessor of the form <field_name>_as_value
187
- if (!has_field &&
188
- (accessor_type == METHOD_GETTER || accessor_type == METHOD_SETTER) &&
189
- name_len > 9 && strncmp(name + name_len - 9, "_as_value", 9) == 0) {
190
- const upb_oneofdef* test_o_wrapper;
191
- const upb_fielddef* test_f_wrapper;
192
- char wrapper_field_name[name_len - 8];
193
-
194
- // Find the field name
195
- strncpy(wrapper_field_name, name, name_len - 9);
196
- wrapper_field_name[name_len - 9] = '\0';
197
-
198
- // Check if field exists and is a wrapper type
199
- if (upb_msgdef_lookupname(self->descriptor->msgdef, wrapper_field_name,
200
- name_len - 9, &test_f_wrapper, &test_o_wrapper) &&
201
- is_wrapper_type_field(test_f_wrapper)) {
202
- // It does exist!
203
- has_field = true;
204
- if (accessor_type == METHOD_SETTER) {
205
- accessor_type = METHOD_WRAPPER_SETTER;
206
- } else {
207
- accessor_type = METHOD_WRAPPER_GETTER;
245
+ return METHOD_UNKNOWN;
246
+ }
247
+
248
+ static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
249
+ int accessor_type) {
250
+ Message* self = ruby_to_Message(_self);
251
+ const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
252
+
253
+ switch (accessor_type) {
254
+ case METHOD_PRESENCE:
255
+ return oneof_field == NULL ? Qfalse : Qtrue;
256
+ case METHOD_CLEAR:
257
+ if (oneof_field != NULL) {
258
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL),
259
+ oneof_field);
208
260
  }
209
- test_o = test_o_wrapper;
210
- test_f = test_f_wrapper;
211
- }
261
+ return Qnil;
262
+ case METHOD_GETTER:
263
+ return oneof_field == NULL
264
+ ? Qnil
265
+ : ID2SYM(rb_intern(upb_FieldDef_Name(oneof_field)));
266
+ case METHOD_SETTER:
267
+ rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
212
268
  }
269
+ rb_raise(rb_eRuntimeError, "Invalid access of oneof field.");
270
+ }
213
271
 
214
- // Look for enum accessor of the form <enum_name>_const
215
- if (!has_field && accessor_type == METHOD_GETTER &&
216
- name_len > 6 && strncmp(name + name_len - 6, "_const", 6) == 0) {
217
- const upb_oneofdef* test_o_enum;
218
- const upb_fielddef* test_f_enum;
219
- char enum_name[name_len - 5];
220
-
221
- // Find enum field name
222
- strncpy(enum_name, name, name_len - 6);
223
- enum_name[name_len - 6] = '\0';
224
-
225
- // Check if enum field exists
226
- if (upb_msgdef_lookupname(self->descriptor->msgdef, enum_name, name_len - 6,
227
- &test_f_enum, &test_o_enum) &&
228
- upb_fielddef_type(test_f_enum) == UPB_TYPE_ENUM) {
229
- // It does exist!
230
- has_field = true;
231
- accessor_type = METHOD_ENUM_GETTER;
232
- test_o = test_o_enum;
233
- test_f = test_f_enum;
272
+ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
273
+ upb_Arena* arena) {
274
+ upb_MessageValue msgval;
275
+ if (upb_FieldDef_IsMap(f)) {
276
+ msgval.map_val = Map_GetUpbMap(val, f, arena);
277
+ } else if (upb_FieldDef_IsRepeated(f)) {
278
+ msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
279
+ } else {
280
+ if (val == Qnil &&
281
+ (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) {
282
+ upb_Message_ClearFieldByDef(msg, f);
283
+ return;
234
284
  }
285
+ msgval =
286
+ Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
235
287
  }
288
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
289
+ }
236
290
 
237
- // Verify the name corresponds to a oneof or field in this message.
238
- if (!has_field) {
239
- return METHOD_UNKNOWN;
291
+ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
292
+ Message* self = ruby_to_Message(_self);
293
+ // This is a special-case: upb_Message_Mutable() for map & array are logically
294
+ // const (they will not change what is serialized) but physically
295
+ // non-const, as they do allocate a repeated field or map. The logical
296
+ // constness means it's ok to do even if the message is frozen.
297
+ upb_Message* msg = (upb_Message*)self->msg;
298
+ upb_Arena* arena = Arena_get(self->arena);
299
+ if (upb_FieldDef_IsMap(f)) {
300
+ upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
301
+ const upb_FieldDef* key_f = map_field_key(f);
302
+ const upb_FieldDef* val_f = map_field_value(f);
303
+ upb_CType key_type = upb_FieldDef_CType(key_f);
304
+ TypeInfo value_type_info = TypeInfo_get(val_f);
305
+ return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
306
+ } else if (upb_FieldDef_IsRepeated(f)) {
307
+ upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
308
+ return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
309
+ } else if (upb_FieldDef_IsSubMessage(f)) {
310
+ if (!upb_Message_HasFieldByDef(self->msg, f)) return Qnil;
311
+ upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
312
+ const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
313
+ return Message_GetRubyWrapper(submsg, m, self->arena);
314
+ } else {
315
+ upb_MessageValue msgval = upb_Message_GetFieldByDef(self->msg, f);
316
+ return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
240
317
  }
318
+ }
241
319
 
242
- // Method calls like 'has_foo?' are not allowed if field "foo" does not have
243
- // a hasbit (e.g. repeated fields or non-message type fields for proto3
244
- // syntax).
245
- if (accessor_type == METHOD_PRESENCE && test_f != NULL) {
246
- if (!upb_fielddef_haspresence(test_f)) return METHOD_UNKNOWN;
320
+ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
321
+ int accessor_type, int argc, VALUE* argv) {
322
+ upb_Arena* arena = Arena_get(Message_GetArena(_self));
247
323
 
248
- // TODO(haberman): remove this case, allow for proto3 oneofs.
249
- if (upb_fielddef_realcontainingoneof(test_f) &&
250
- upb_filedef_syntax(upb_fielddef_file(test_f)) == UPB_SYNTAX_PROTO3) {
251
- return METHOD_UNKNOWN;
324
+ switch (accessor_type) {
325
+ case METHOD_SETTER:
326
+ Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
327
+ return Qnil;
328
+ case METHOD_CLEAR:
329
+ upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f);
330
+ return Qnil;
331
+ case METHOD_PRESENCE:
332
+ if (!upb_FieldDef_HasPresence(f)) {
333
+ rb_raise(rb_eRuntimeError, "Field does not have presence.");
334
+ }
335
+ return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f);
336
+ case METHOD_WRAPPER_GETTER: {
337
+ Message* self = ruby_to_Message(_self);
338
+ if (upb_Message_HasFieldByDef(self->msg, f)) {
339
+ PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
340
+ !upb_FieldDef_IsRepeated(f));
341
+ upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f);
342
+ const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
343
+ const upb_FieldDef* value_f =
344
+ upb_MessageDef_FindFieldByNumber(wrapper_m, 1);
345
+ upb_MessageValue value =
346
+ upb_Message_GetFieldByDef(wrapper.msg_val, value_f);
347
+ return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
348
+ } else {
349
+ return Qnil;
350
+ }
252
351
  }
352
+ case METHOD_WRAPPER_SETTER: {
353
+ upb_Message* msg = Message_GetMutable(_self, NULL);
354
+ if (argv[1] == Qnil) {
355
+ upb_Message_ClearFieldByDef(msg, f);
356
+ } else {
357
+ const upb_FieldDef* val_f =
358
+ upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1);
359
+ upb_MessageValue msgval = Convert_RubyToUpb(
360
+ argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
361
+ upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
362
+ upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
363
+ }
364
+ return Qnil;
365
+ }
366
+ case METHOD_ENUM_GETTER: {
367
+ upb_MessageValue msgval =
368
+ upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
369
+
370
+ if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
371
+ // Map repeated fields to a new type with ints
372
+ VALUE arr = rb_ary_new();
373
+ size_t i, n = upb_Array_Size(msgval.array_val);
374
+ for (i = 0; i < n; i++) {
375
+ upb_MessageValue elem = upb_Array_Get(msgval.array_val, i);
376
+ rb_ary_push(arr, INT2NUM(elem.int32_val));
377
+ }
378
+ return arr;
379
+ } else {
380
+ return INT2NUM(msgval.int32_val);
381
+ }
382
+ }
383
+ case METHOD_GETTER:
384
+ return Message_getfield(_self, f);
385
+ default:
386
+ rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d",
387
+ accessor_type);
253
388
  }
254
-
255
- *o = test_o;
256
- *f = test_f;
257
- return accessor_type;
258
389
  }
259
390
 
260
391
  /*
@@ -284,111 +415,56 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
284
415
  * true if the field 'fieldname' is set in the message object, else false. For
285
416
  * 'proto3' syntax, calling this for a basic type field will result in an error.
286
417
  */
287
- VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
288
- MessageHeader* self;
289
- const upb_oneofdef* o;
290
- const upb_fielddef* f;
418
+ static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
419
+ Message* self = ruby_to_Message(_self);
420
+ const upb_OneofDef* o;
421
+ const upb_FieldDef* f;
291
422
  int accessor_type;
292
423
 
293
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
294
424
  if (argc < 1) {
295
425
  rb_raise(rb_eArgError, "Expected method name as first argument.");
296
426
  }
297
427
 
298
428
  accessor_type = extract_method_call(argv[0], self, &f, &o);
299
- if (accessor_type == METHOD_UNKNOWN || (o == NULL && f == NULL) ) {
300
- return rb_call_super(argc, argv);
301
- } else if (accessor_type == METHOD_SETTER || accessor_type == METHOD_WRAPPER_SETTER) {
302
- if (argc != 2) {
303
- rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
304
- }
305
- rb_check_frozen(_self);
306
- } else if (argc != 1) {
307
- rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
308
- }
309
-
310
- // Return which of the oneof fields are set
311
- if (o != NULL) {
312
- const upb_fielddef* oneof_field = which_oneof_field(self, o);
313
429
 
314
- if (accessor_type == METHOD_SETTER) {
315
- rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
316
- }
430
+ if (accessor_type == METHOD_UNKNOWN) return rb_call_super(argc, argv);
317
431
 
318
- if (accessor_type == METHOD_PRESENCE) {
319
- return oneof_field == NULL ? Qfalse : Qtrue;
320
- } else if (accessor_type == METHOD_CLEAR) {
321
- if (oneof_field != NULL) {
322
- layout_clear(self->descriptor->layout, Message_data(self), oneof_field);
432
+ // Validate argument count.
433
+ switch (accessor_type) {
434
+ case METHOD_SETTER:
435
+ case METHOD_WRAPPER_SETTER:
436
+ if (argc != 2) {
437
+ rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
323
438
  }
324
- return Qnil;
325
- } else {
326
- // METHOD_ACCESSOR
327
- return oneof_field == NULL ? Qnil :
328
- ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
329
- }
330
- // Otherwise we're operating on a single proto field
331
- } else if (accessor_type == METHOD_SETTER) {
332
- layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
333
- return Qnil;
334
- } else if (accessor_type == METHOD_CLEAR) {
335
- layout_clear(self->descriptor->layout, Message_data(self), f);
336
- return Qnil;
337
- } else if (accessor_type == METHOD_PRESENCE) {
338
- return layout_has(self->descriptor->layout, Message_data(self), f);
339
- } else if (accessor_type == METHOD_WRAPPER_GETTER) {
340
- VALUE value = layout_get(self->descriptor->layout, Message_data(self), f);
341
- switch (TYPE(value)) {
342
- case T_DATA:
343
- return rb_funcall(value, rb_intern("value"), 0);
344
- case T_NIL:
345
- return Qnil;
346
- default:
347
- return value;
348
- }
349
- } else if (accessor_type == METHOD_WRAPPER_SETTER) {
350
- VALUE wrapper = ruby_wrapper_type(
351
- field_type_class(self->descriptor->layout, f), argv[1]);
352
- layout_set(self->descriptor->layout, Message_data(self), f, wrapper);
353
- return Qnil;
354
- } else if (accessor_type == METHOD_ENUM_GETTER) {
355
- VALUE enum_type = field_type_class(self->descriptor->layout, f);
356
- VALUE method = rb_intern("const_get");
357
- VALUE raw_value = layout_get(self->descriptor->layout, Message_data(self), f);
358
-
359
- // Map repeated fields to a new type with ints
360
- if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
361
- int array_size = FIX2INT(rb_funcall(raw_value, rb_intern("length"), 0));
362
- int i;
363
- VALUE array_args[1] = { ID2SYM(rb_intern("int64")) };
364
- VALUE array = rb_class_new_instance(1, array_args, CLASS_OF(raw_value));
365
- for (i = 0; i < array_size; i++) {
366
- VALUE entry = rb_funcall(enum_type, method, 1, rb_funcall(raw_value,
367
- rb_intern("at"), 1, INT2NUM(i)));
368
- rb_funcall(array, rb_intern("push"), 1, entry);
439
+ rb_check_frozen(_self);
440
+ break;
441
+ default:
442
+ if (argc != 1) {
443
+ rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
369
444
  }
370
- return array;
371
- }
372
- // Convert the value for singular fields
373
- return rb_funcall(enum_type, method, 1, raw_value);
445
+ break;
446
+ }
447
+
448
+ // Dispatch accessor.
449
+ if (o != NULL) {
450
+ return Message_oneof_accessor(_self, o, accessor_type);
374
451
  } else {
375
- return layout_get(self->descriptor->layout, Message_data(self), f);
452
+ return Message_field_accessor(_self, f, accessor_type, argc, argv);
376
453
  }
377
454
  }
378
455
 
379
-
380
- VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
381
- MessageHeader* self;
382
- const upb_oneofdef* o;
383
- const upb_fielddef* f;
456
+ static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
457
+ Message* self = ruby_to_Message(_self);
458
+ const upb_OneofDef* o;
459
+ const upb_FieldDef* f;
384
460
  int accessor_type;
385
461
 
386
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
387
462
  if (argc < 1) {
388
463
  rb_raise(rb_eArgError, "Expected method name as first argument.");
389
464
  }
390
465
 
391
466
  accessor_type = extract_method_call(argv[0], self, &f, &o);
467
+
392
468
  if (accessor_type == METHOD_UNKNOWN) {
393
469
  return rb_call_super(argc, argv);
394
470
  } else if (o != NULL) {
@@ -398,17 +474,120 @@ VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
398
474
  }
399
475
  }
400
476
 
401
- VALUE create_submsg_from_hash(const MessageLayout* layout,
402
- const upb_fielddef* f, VALUE hash) {
403
- VALUE args[1] = { hash };
404
- return rb_class_new_instance(1, args, field_type_class(layout, f));
477
+ void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
478
+ upb_Arena* arena);
479
+
480
+ typedef struct {
481
+ upb_Map* map;
482
+ TypeInfo key_type;
483
+ TypeInfo val_type;
484
+ upb_Arena* arena;
485
+ } MapInit;
486
+
487
+ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
488
+ MapInit* map_init = (MapInit*)_self;
489
+ upb_MessageValue k, v;
490
+ k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
491
+
492
+ if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
493
+ const upb_MiniTable* t =
494
+ upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
495
+ upb_Message* msg = upb_Message_New(t, map_init->arena);
496
+ Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
497
+ map_init->arena);
498
+ v.msg_val = msg;
499
+ } else {
500
+ v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena);
501
+ }
502
+ upb_Map_Set(map_init->map, k, v, map_init->arena);
503
+ return ST_CONTINUE;
504
+ }
505
+
506
+ static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val,
507
+ upb_Arena* arena) {
508
+ const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
509
+ const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
510
+ const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
511
+ if (TYPE(val) != T_HASH) {
512
+ rb_raise(rb_eArgError,
513
+ "Expected Hash object as initializer value for map field '%s' "
514
+ "(given %s).",
515
+ upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
516
+ }
517
+ MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena};
518
+ rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init);
519
+ }
520
+
521
+ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
522
+ upb_Arena* arena) {
523
+ if (info.type == kUpb_CType_Message) {
524
+ upb_MessageValue msgval;
525
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
526
+ upb_Message* msg = upb_Message_New(t, arena);
527
+ Message_InitFromValue(msg, info.def.msgdef, val, arena);
528
+ msgval.msg_val = msg;
529
+ return msgval;
530
+ } else {
531
+ return Convert_RubyToUpb(val, "", info, arena);
532
+ }
533
+ }
534
+
535
+ static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f,
536
+ VALUE val, upb_Arena* arena) {
537
+ TypeInfo type_info = TypeInfo_get(f);
538
+
539
+ if (TYPE(val) != T_ARRAY) {
540
+ rb_raise(rb_eArgError,
541
+ "Expected array as initializer value for repeated field '%s' "
542
+ "(given %s).",
543
+ upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
544
+ }
545
+
546
+ for (int i = 0; i < RARRAY_LEN(val); i++) {
547
+ VALUE entry = rb_ary_entry(val, i);
548
+ upb_MessageValue msgval;
549
+ if (upb_FieldDef_IsSubMessage(f) && TYPE(entry) == T_HASH) {
550
+ msgval = MessageValue_FromValue(entry, type_info, arena);
551
+ } else {
552
+ msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena);
553
+ }
554
+ upb_Array_Append(arr, msgval, arena);
555
+ }
556
+ }
557
+
558
+ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
559
+ VALUE val, upb_Arena* arena) {
560
+ if (TYPE(val) == T_NIL) return;
561
+
562
+ if (upb_FieldDef_IsMap(f)) {
563
+ upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
564
+ Map_InitFromValue(map, f, val, arena);
565
+ } else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
566
+ upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
567
+ RepeatedField_InitFromValue(arr, f, val, arena);
568
+ } else if (upb_FieldDef_IsSubMessage(f)) {
569
+ if (TYPE(val) == T_HASH) {
570
+ upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
571
+ Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena);
572
+ } else {
573
+ Message_setfield(msg, f, val, arena);
574
+ }
575
+ } else {
576
+ upb_MessageValue msgval =
577
+ Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
578
+ upb_Message_SetFieldByDef(msg, f, msgval, arena);
579
+ }
405
580
  }
406
581
 
407
- int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
408
- MessageHeader* self;
409
- char *name;
410
- const upb_fielddef* f;
411
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
582
+ typedef struct {
583
+ upb_Message* msg;
584
+ const upb_MessageDef* msgdef;
585
+ upb_Arena* arena;
586
+ } MsgInit;
587
+
588
+ static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
589
+ MsgInit* msg_init = (MsgInit*)_self;
590
+ const char* name;
412
591
 
413
592
  if (TYPE(key) == T_STRING) {
414
593
  name = RSTRING_PTR(key);
@@ -416,55 +595,31 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
416
595
  name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
417
596
  } else {
418
597
  rb_raise(rb_eArgError,
419
- "Expected string or symbols as hash keys when initializing proto from hash.");
598
+ "Expected string or symbols as hash keys when initializing proto "
599
+ "from hash.");
420
600
  }
421
601
 
422
- f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
602
+ const upb_FieldDef* f =
603
+ upb_MessageDef_FindFieldByName(msg_init->msgdef, name);
604
+
423
605
  if (f == NULL) {
424
606
  rb_raise(rb_eArgError,
425
607
  "Unknown field name '%s' in initialization map entry.", name);
426
608
  }
427
609
 
428
- if (TYPE(val) == T_NIL) {
429
- return 0;
430
- }
431
-
432
- if (is_map_field(f)) {
433
- VALUE map;
434
-
435
- if (TYPE(val) != T_HASH) {
436
- rb_raise(rb_eArgError,
437
- "Expected Hash object as initializer value for map field '%s' (given %s).",
438
- name, rb_class2name(CLASS_OF(val)));
439
- }
440
- map = layout_get(self->descriptor->layout, Message_data(self), f);
441
- Map_merge_into_self(map, val);
442
- } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
443
- VALUE ary;
444
- int i;
445
-
446
- if (TYPE(val) != T_ARRAY) {
447
- rb_raise(rb_eArgError,
448
- "Expected array as initializer value for repeated field '%s' (given %s).",
449
- name, rb_class2name(CLASS_OF(val)));
450
- }
451
- ary = layout_get(self->descriptor->layout, Message_data(self), f);
452
- for (i = 0; i < RARRAY_LEN(val); i++) {
453
- VALUE entry = rb_ary_entry(val, i);
454
- if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
455
- entry = create_submsg_from_hash(self->descriptor->layout, f, entry);
456
- }
610
+ Message_InitFieldFromValue(msg_init->msg, f, val, msg_init->arena);
611
+ return ST_CONTINUE;
612
+ }
457
613
 
458
- RepeatedField_push(ary, entry);
459
- }
614
+ void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
615
+ upb_Arena* arena) {
616
+ MsgInit msg_init = {msg, m, arena};
617
+ if (TYPE(val) == T_HASH) {
618
+ rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init);
460
619
  } else {
461
- if (TYPE(val) == T_HASH && upb_fielddef_issubmsg(f)) {
462
- val = create_submsg_from_hash(self->descriptor->layout, f, val);
463
- }
464
-
465
- layout_set(self->descriptor->layout, Message_data(self), f, val);
620
+ rb_raise(rb_eArgError, "Expected hash arguments or message, not %s",
621
+ rb_class2name(CLASS_OF(val)));
466
622
  }
467
- return 0;
468
623
  }
469
624
 
470
625
  /*
@@ -479,12 +634,14 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
479
634
  * have been added to a pool. The method definitions described here on the
480
635
  * Message class are provided on each concrete message class.
481
636
  */
482
- VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
483
- MessageHeader* self;
484
- VALUE hash_args;
485
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
637
+ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
638
+ Message* self = ruby_to_Message(_self);
639
+ VALUE arena_rb = Arena_new();
640
+ upb_Arena* arena = Arena_get(arena_rb);
641
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
642
+ upb_Message* msg = upb_Message_New(t, arena);
486
643
 
487
- layout_init(self->descriptor->layout, Message_data(self));
644
+ Message_InitPtr(_self, msg, arena_rb);
488
645
 
489
646
  if (argc == 0) {
490
647
  return Qnil;
@@ -492,12 +649,7 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
492
649
  if (argc != 1) {
493
650
  rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
494
651
  }
495
- hash_args = argv[0];
496
- if (TYPE(hash_args) != T_HASH) {
497
- rb_raise(rb_eArgError, "Expected hash arguments.");
498
- }
499
-
500
- rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
652
+ Message_InitFromValue((upb_Message*)self->msg, self->msgdef, argv[0], arena);
501
653
  return Qnil;
502
654
  }
503
655
 
@@ -507,37 +659,28 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
507
659
  *
508
660
  * Performs a shallow copy of this message and returns the new copy.
509
661
  */
510
- VALUE Message_dup(VALUE _self) {
511
- MessageHeader* self;
512
- VALUE new_msg;
513
- MessageHeader* new_msg_self;
514
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
515
-
516
- new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
517
- TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
518
-
519
- layout_dup(self->descriptor->layout,
520
- Message_data(new_msg_self),
521
- Message_data(self));
522
-
662
+ static VALUE Message_dup(VALUE _self) {
663
+ Message* self = ruby_to_Message(_self);
664
+ VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
665
+ Message* new_msg_self = ruby_to_Message(new_msg);
666
+ const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
667
+ upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
668
+ Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
523
669
  return new_msg;
524
670
  }
525
671
 
526
- // Internal only; used by Google::Protobuf.deep_copy.
527
- VALUE Message_deep_copy(VALUE _self) {
528
- MessageHeader* self;
529
- MessageHeader* new_msg_self;
530
- VALUE new_msg;
531
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
532
-
533
- new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
534
- TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
535
-
536
- layout_deep_copy(self->descriptor->layout,
537
- Message_data(new_msg_self),
538
- Message_data(self));
539
-
540
- return new_msg;
672
+ // Support function for Message_eq, and also used by other #eq functions.
673
+ bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
674
+ const upb_MessageDef* m) {
675
+ upb_Status status;
676
+ upb_Status_Clear(&status);
677
+ bool return_value = shared_Message_Equal(m1, m2, m, &status);
678
+ if (upb_Status_IsOk(&status)) {
679
+ return return_value;
680
+ } else {
681
+ rb_raise(cParseError, "Message_Equal(): %s",
682
+ upb_Status_ErrorMessage(&status));
683
+ }
541
684
  }
542
685
 
543
686
  /*
@@ -549,22 +692,27 @@ VALUE Message_deep_copy(VALUE _self) {
549
692
  * method's semantics (a more efficient comparison may actually be done if the
550
693
  * field is of a primitive type).
551
694
  */
552
- VALUE Message_eq(VALUE _self, VALUE _other) {
553
- MessageHeader* self;
554
- MessageHeader* other;
555
- if (TYPE(_self) != TYPE(_other)) {
556
- return Qfalse;
557
- }
558
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
559
- TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
695
+ static VALUE Message_eq(VALUE _self, VALUE _other) {
696
+ if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse;
560
697
 
561
- if (self->descriptor != other->descriptor) {
562
- return Qfalse;
563
- }
698
+ Message* self = ruby_to_Message(_self);
699
+ Message* other = ruby_to_Message(_other);
700
+ assert(self->msgdef == other->msgdef);
564
701
 
565
- return layout_eq(self->descriptor->layout,
566
- Message_data(self),
567
- Message_data(other));
702
+ return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
703
+ }
704
+
705
+ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
706
+ uint64_t seed) {
707
+ upb_Status status;
708
+ upb_Status_Clear(&status);
709
+ uint64_t return_value = shared_Message_Hash(msg, m, seed, &status);
710
+ if (upb_Status_IsOk(&status)) {
711
+ return return_value;
712
+ } else {
713
+ rb_raise(cParseError, "Message_Hash(): %s",
714
+ upb_Status_ErrorMessage(&status));
715
+ }
568
716
  }
569
717
 
570
718
  /*
@@ -573,11 +721,12 @@ VALUE Message_eq(VALUE _self, VALUE _other) {
573
721
  *
574
722
  * Returns a hash value that represents this message's field values.
575
723
  */
576
- VALUE Message_hash(VALUE _self) {
577
- MessageHeader* self;
578
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
579
-
580
- return layout_hash(self->descriptor->layout, Message_data(self));
724
+ static VALUE Message_hash(VALUE _self) {
725
+ Message* self = ruby_to_Message(_self);
726
+ uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0);
727
+ // RUBY_FIXNUM_MAX should be one less than a power of 2.
728
+ assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0);
729
+ return INT2FIX(hash_value & RUBY_FIXNUM_MAX);
581
730
  }
582
731
 
583
732
  /*
@@ -588,81 +737,121 @@ VALUE Message_hash(VALUE _self) {
588
737
  * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
589
738
  * field's value is represented according to its own #inspect method.
590
739
  */
591
- VALUE Message_inspect(VALUE _self) {
592
- MessageHeader* self;
593
- VALUE str;
594
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
740
+ static VALUE Message_inspect(VALUE _self) {
741
+ Message* self = ruby_to_Message(_self);
595
742
 
596
- str = rb_str_new2("<");
597
- str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
598
- str = rb_str_cat2(str, ": ");
599
- str = rb_str_append(str, layout_inspect(
600
- self->descriptor->layout, Message_data(self)));
601
- str = rb_str_cat2(str, ">");
602
- return str;
743
+ StringBuilder* builder = StringBuilder_New();
744
+ Message_PrintMessage(builder, self->msg, self->msgdef);
745
+ VALUE ret = StringBuilder_ToRubyString(builder);
746
+ StringBuilder_Free(builder);
747
+ return ret;
603
748
  }
604
749
 
605
- /*
606
- * call-seq:
607
- * Message.to_h => {}
608
- *
609
- * Returns the message as a Ruby Hash object, with keys as symbols.
610
- */
611
- VALUE Message_to_h(VALUE _self) {
612
- MessageHeader* self;
613
- VALUE hash = rb_hash_new();
614
- upb_msg_field_iter it;
615
- bool is_proto2;
616
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
617
-
618
- // We currently have a few behaviors that are specific to proto2.
619
- // This is unfortunate, we should key behaviors off field attributes (like
620
- // whether a field has presence), not proto2 vs. proto3. We should see if we
621
- // can change this without breaking users.
622
- is_proto2 =
623
- upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2;
624
-
625
- for (upb_msg_field_begin(&it, self->descriptor->msgdef);
626
- !upb_msg_field_done(&it);
627
- upb_msg_field_next(&it)) {
628
- const upb_fielddef* field = upb_msg_iter_field(&it);
629
- VALUE msg_value;
630
- VALUE msg_key;
750
+ // Support functions for Message_to_h //////////////////////////////////////////
751
+
752
+ static VALUE RepeatedField_CreateArray(const upb_Array* arr,
753
+ TypeInfo type_info) {
754
+ int size = arr ? upb_Array_Size(arr) : 0;
755
+ VALUE ary = rb_ary_new2(size);
756
+
757
+ for (int i = 0; i < size; i++) {
758
+ upb_MessageValue msgval = upb_Array_Get(arr, i);
759
+ VALUE val = Scalar_CreateHash(msgval, type_info);
760
+ rb_ary_push(ary, val);
761
+ }
762
+
763
+ return ary;
764
+ }
631
765
 
632
- // Do not include fields that are not present (oneof or optional fields).
633
- if (is_proto2 && upb_fielddef_haspresence(field) &&
634
- !layout_has(self->descriptor->layout, Message_data(self), field)) {
766
+ static VALUE Message_CreateHash(const upb_Message* msg,
767
+ const upb_MessageDef* m) {
768
+ if (!msg) return Qnil;
769
+
770
+ VALUE hash = rb_hash_new();
771
+ size_t iter = kUpb_Message_Begin;
772
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m));
773
+ const upb_FieldDef* field;
774
+ upb_MessageValue val;
775
+
776
+ while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) {
777
+ if (upb_FieldDef_IsExtension(field)) {
778
+ // TODO: allow extensions once we have decided what naming scheme the
779
+ // symbol should use. eg. :"[pkg.ext]"
635
780
  continue;
636
781
  }
637
782
 
638
- msg_value = layout_get(self->descriptor->layout, Message_data(self), field);
639
- msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
640
- if (is_map_field(field)) {
641
- msg_value = Map_to_h(msg_value);
642
- } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
643
- msg_value = RepeatedField_to_ary(msg_value);
644
- if (is_proto2 && RARRAY_LEN(msg_value) == 0) {
645
- continue;
646
- }
647
-
648
- if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
649
- int i;
650
- for (i = 0; i < RARRAY_LEN(msg_value); i++) {
651
- VALUE elem = rb_ary_entry(msg_value, i);
652
- rb_ary_store(msg_value, i, Message_to_h(elem));
653
- }
654
- }
783
+ TypeInfo type_info = TypeInfo_get(field);
784
+ VALUE msg_value;
655
785
 
656
- } else if (msg_value != Qnil &&
657
- upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
658
- msg_value = Message_to_h(msg_value);
786
+ if (upb_FieldDef_IsMap(field)) {
787
+ const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
788
+ const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
789
+ const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
790
+ upb_CType key_type = upb_FieldDef_CType(key_f);
791
+ msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f));
792
+ } else if (upb_FieldDef_IsRepeated(field)) {
793
+ msg_value = RepeatedField_CreateArray(val.array_val, type_info);
794
+ } else {
795
+ msg_value = Scalar_CreateHash(val, type_info);
659
796
  }
797
+
798
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
660
799
  rb_hash_aset(hash, msg_key, msg_value);
661
800
  }
801
+
662
802
  return hash;
663
803
  }
664
804
 
805
+ VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
806
+ if (type_info.type == kUpb_CType_Message) {
807
+ return Message_CreateHash(msgval.msg_val, type_info.def.msgdef);
808
+ } else {
809
+ return Convert_UpbToRuby(msgval, type_info, Qnil);
810
+ }
811
+ }
812
+
813
+ /*
814
+ * call-seq:
815
+ * Message.to_h => {}
816
+ *
817
+ * Returns the message as a Ruby Hash object, with keys as symbols.
818
+ */
819
+ static VALUE Message_to_h(VALUE _self) {
820
+ Message* self = ruby_to_Message(_self);
821
+ return Message_CreateHash(self->msg, self->msgdef);
822
+ }
665
823
 
824
+ /*
825
+ * call-seq:
826
+ * Message.freeze => self
827
+ *
828
+ * Freezes the message object. We have to intercept this so we can pin the
829
+ * Ruby object into memory so we don't forget it's frozen.
830
+ */
831
+ VALUE Message_freeze(VALUE _self) {
832
+ Message* self = ruby_to_Message(_self);
833
+
834
+ if (RB_OBJ_FROZEN(_self)) return _self;
835
+ Arena_Pin(self->arena, _self);
836
+ RB_OBJ_FREEZE(_self);
837
+
838
+ int n = upb_MessageDef_FieldCount(self->msgdef);
839
+ for (int i = 0; i < n; i++) {
840
+ const upb_FieldDef* f = upb_MessageDef_Field(self->msgdef, i);
841
+ VALUE field = Message_getfield(_self, f);
842
+
843
+ if (field != Qnil) {
844
+ if (upb_FieldDef_IsMap(f)) {
845
+ Map_freeze(field);
846
+ } else if (upb_FieldDef_IsRepeated(f)) {
847
+ RepeatedField_freeze(field);
848
+ } else if (upb_FieldDef_IsSubMessage(f)) {
849
+ Message_freeze(field);
850
+ }
851
+ }
852
+ }
853
+ return _self;
854
+ }
666
855
 
667
856
  /*
668
857
  * call-seq:
@@ -671,16 +860,18 @@ VALUE Message_to_h(VALUE _self) {
671
860
  * Accesses a field's value by field name. The provided field name should be a
672
861
  * string.
673
862
  */
674
- VALUE Message_index(VALUE _self, VALUE field_name) {
675
- MessageHeader* self;
676
- const upb_fielddef* field;
677
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
863
+ static VALUE Message_index(VALUE _self, VALUE field_name) {
864
+ Message* self = ruby_to_Message(_self);
865
+ const upb_FieldDef* field;
866
+
678
867
  Check_Type(field_name, T_STRING);
679
- field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
868
+ field = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
869
+
680
870
  if (field == NULL) {
681
871
  return Qnil;
682
872
  }
683
- return layout_get(self->descriptor->layout, Message_data(self), field);
873
+
874
+ return Message_getfield(_self, field);
684
875
  }
685
876
 
686
877
  /*
@@ -690,19 +881,274 @@ VALUE Message_index(VALUE _self, VALUE field_name) {
690
881
  * Sets a field's value by field name. The provided field name should be a
691
882
  * string.
692
883
  */
693
- VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
694
- MessageHeader* self;
695
- const upb_fielddef* field;
696
- TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
884
+ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
885
+ Message* self = ruby_to_Message(_self);
886
+ const upb_FieldDef* f;
887
+ upb_MessageValue val;
888
+ upb_Arena* arena = Arena_get(self->arena);
889
+
697
890
  Check_Type(field_name, T_STRING);
698
- field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
699
- if (field == NULL) {
891
+ f = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
892
+
893
+ if (f == NULL) {
700
894
  rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
701
895
  }
702
- layout_set(self->descriptor->layout, Message_data(self), field, value);
896
+
897
+ val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
898
+ upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
899
+
703
900
  return Qnil;
704
901
  }
705
902
 
903
+ /*
904
+ * call-seq:
905
+ * MessageClass.decode(data, options) => message
906
+ *
907
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
908
+ * format) under the interpretation given by this message class's definition
909
+ * and returns a message object with the corresponding field values.
910
+ * @param options [Hash] options for the decoder
911
+ * recursion_limit: set to maximum decoding depth for message (default is 64)
912
+ */
913
+ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
914
+ VALUE data = argv[0];
915
+ int options = 0;
916
+
917
+ if (argc < 1 || argc > 2) {
918
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
919
+ }
920
+
921
+ if (argc == 2) {
922
+ VALUE hash_args = argv[1];
923
+ if (TYPE(hash_args) != T_HASH) {
924
+ rb_raise(rb_eArgError, "Expected hash arguments.");
925
+ }
926
+
927
+ VALUE depth =
928
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
929
+
930
+ if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
931
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
932
+ }
933
+ }
934
+
935
+ if (TYPE(data) != T_STRING) {
936
+ rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
937
+ }
938
+
939
+ return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options,
940
+ klass, /*freeze*/ false);
941
+ }
942
+
943
+ VALUE Message_decode_bytes(int size, const char* bytes, int options,
944
+ VALUE klass, bool freeze) {
945
+ VALUE msg_rb = initialize_rb_class_with_no_args(klass);
946
+ Message* msg = ruby_to_Message(msg_rb);
947
+
948
+ const upb_FileDef* file = upb_MessageDef_File(msg->msgdef);
949
+ const upb_ExtensionRegistry* extreg =
950
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
951
+ upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
952
+ upb_MessageDef_MiniTable(msg->msgdef),
953
+ extreg, options, Arena_get(msg->arena));
954
+ if (status != kUpb_DecodeStatus_Ok) {
955
+ rb_raise(cParseError, "Error occurred during parsing");
956
+ }
957
+ if (freeze) {
958
+ Message_freeze(msg_rb);
959
+ }
960
+ return msg_rb;
961
+ }
962
+
963
+ /*
964
+ * call-seq:
965
+ * MessageClass.decode_json(data, options = {}) => message
966
+ *
967
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
968
+ * format) under the interpretration given by this message class's definition
969
+ * and returns a message object with the corresponding field values.
970
+ *
971
+ * @param options [Hash] options for the decoder
972
+ * ignore_unknown_fields: set true to ignore unknown fields (default is to
973
+ * raise an error)
974
+ */
975
+ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
976
+ VALUE data = argv[0];
977
+ int options = 0;
978
+ upb_Status status;
979
+
980
+ if (argc < 1 || argc > 2) {
981
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
982
+ }
983
+
984
+ if (argc == 2) {
985
+ VALUE hash_args = argv[1];
986
+ if (TYPE(hash_args) != T_HASH) {
987
+ rb_raise(rb_eArgError, "Expected hash arguments.");
988
+ }
989
+
990
+ if (RTEST(rb_hash_lookup2(
991
+ hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) {
992
+ options |= upb_JsonDecode_IgnoreUnknown;
993
+ }
994
+ }
995
+
996
+ if (TYPE(data) != T_STRING) {
997
+ rb_raise(rb_eArgError, "Expected string for JSON data.");
998
+ }
999
+
1000
+ // TODO: Check and respect string encoding. If not UTF-8, we need to
1001
+ // convert, because string handlers pass data directly to message string
1002
+ // fields.
1003
+
1004
+ VALUE msg_rb = initialize_rb_class_with_no_args(klass);
1005
+ Message* msg = ruby_to_Message(msg_rb);
1006
+
1007
+ // We don't allow users to decode a wrapper type directly.
1008
+ if (IsWrapper(msg->msgdef)) {
1009
+ rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly.");
1010
+ }
1011
+
1012
+ upb_Status_Clear(&status);
1013
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1014
+ if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
1015
+ (upb_Message*)msg->msg, msg->msgdef, pool, options,
1016
+ Arena_get(msg->arena), &status)) {
1017
+ rb_raise(cParseError, "Error occurred during parsing: %s",
1018
+ upb_Status_ErrorMessage(&status));
1019
+ }
1020
+
1021
+ return msg_rb;
1022
+ }
1023
+
1024
+ /*
1025
+ * call-seq:
1026
+ * MessageClass.encode(msg, options) => bytes
1027
+ *
1028
+ * Encodes the given message object to its serialized form in protocol buffers
1029
+ * wire format.
1030
+ * @param options [Hash] options for the encoder
1031
+ * recursion_limit: set to maximum encoding depth for message (default is 64)
1032
+ */
1033
+ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1034
+ Message* msg = ruby_to_Message(argv[0]);
1035
+ int options = 0;
1036
+ char* data;
1037
+ size_t size;
1038
+
1039
+ if (CLASS_OF(argv[0]) != klass) {
1040
+ rb_raise(rb_eArgError, "Message of wrong type.");
1041
+ }
1042
+
1043
+ if (argc < 1 || argc > 2) {
1044
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1045
+ }
1046
+
1047
+ if (argc == 2) {
1048
+ VALUE hash_args = argv[1];
1049
+ if (TYPE(hash_args) != T_HASH) {
1050
+ rb_raise(rb_eArgError, "Expected hash arguments.");
1051
+ }
1052
+ VALUE depth =
1053
+ rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
1054
+
1055
+ if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
1056
+ options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
1057
+ }
1058
+ }
1059
+
1060
+ upb_Arena* arena = upb_Arena_New();
1061
+
1062
+ upb_EncodeStatus status =
1063
+ upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
1064
+ arena, &data, &size);
1065
+
1066
+ if (status == kUpb_EncodeStatus_Ok) {
1067
+ VALUE ret = rb_str_new(data, size);
1068
+ rb_enc_associate(ret, rb_ascii8bit_encoding());
1069
+ upb_Arena_Free(arena);
1070
+ return ret;
1071
+ } else {
1072
+ upb_Arena_Free(arena);
1073
+ rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)");
1074
+ }
1075
+ }
1076
+
1077
+ /*
1078
+ * call-seq:
1079
+ * MessageClass.encode_json(msg, options = {}) => json_string
1080
+ *
1081
+ * Encodes the given message object into its serialized JSON representation.
1082
+ * @param options [Hash] options for the decoder
1083
+ * preserve_proto_fieldnames: set true to use original fieldnames (default is
1084
+ * to camelCase) emit_defaults: set true to emit 0/false values (default is to
1085
+ * omit them)
1086
+ */
1087
+ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1088
+ Message* msg = ruby_to_Message(argv[0]);
1089
+ int options = 0;
1090
+ char buf[1024];
1091
+ size_t size;
1092
+ upb_Status status;
1093
+
1094
+ if (argc < 1 || argc > 2) {
1095
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1096
+ }
1097
+
1098
+ if (argc == 2) {
1099
+ VALUE hash_args = argv[1];
1100
+ if (TYPE(hash_args) != T_HASH) {
1101
+ if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1,
1102
+ rb_str_new2("to_h")))) {
1103
+ hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0);
1104
+ } else {
1105
+ rb_raise(rb_eArgError, "Expected hash arguments.");
1106
+ }
1107
+ }
1108
+
1109
+ if (RTEST(rb_hash_lookup2(hash_args,
1110
+ ID2SYM(rb_intern("preserve_proto_fieldnames")),
1111
+ Qfalse))) {
1112
+ options |= upb_JsonEncode_UseProtoNames;
1113
+ }
1114
+
1115
+ if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")),
1116
+ Qfalse))) {
1117
+ options |= upb_JsonEncode_EmitDefaults;
1118
+ }
1119
+
1120
+ if (RTEST(rb_hash_lookup2(hash_args,
1121
+ ID2SYM(rb_intern("format_enums_as_integers")),
1122
+ Qfalse))) {
1123
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
1124
+ }
1125
+ }
1126
+
1127
+ upb_Status_Clear(&status);
1128
+ const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
1129
+ size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
1130
+ &status);
1131
+
1132
+ if (!upb_Status_IsOk(&status)) {
1133
+ rb_raise(cParseError, "Error occurred during encoding: %s",
1134
+ upb_Status_ErrorMessage(&status));
1135
+ }
1136
+
1137
+ VALUE ret;
1138
+ if (size >= sizeof(buf)) {
1139
+ char* buf2 = malloc(size + 1);
1140
+ upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
1141
+ &status);
1142
+ ret = rb_str_new(buf2, size);
1143
+ free(buf2);
1144
+ } else {
1145
+ ret = rb_str_new(buf, size);
1146
+ }
1147
+
1148
+ rb_enc_associate(ret, rb_utf8_encoding());
1149
+ return ret;
1150
+ }
1151
+
706
1152
  /*
707
1153
  * call-seq:
708
1154
  * Message.descriptor => descriptor
@@ -710,16 +1156,15 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
710
1156
  * Class method that returns the Descriptor instance corresponding to this
711
1157
  * message class's type.
712
1158
  */
713
- VALUE Message_descriptor(VALUE klass) {
1159
+ static VALUE Message_descriptor(VALUE klass) {
714
1160
  return rb_ivar_get(klass, descriptor_instancevar_interned);
715
1161
  }
716
1162
 
717
1163
  VALUE build_class_from_descriptor(VALUE descriptor) {
718
- Descriptor* desc = ruby_to_Descriptor(descriptor);
719
- const char *name;
1164
+ const char* name;
720
1165
  VALUE klass;
721
1166
 
722
- name = upb_msgdef_fullname(desc->msgdef);
1167
+ name = upb_MessageDef_FullName(Descriptor_GetMsgDef(descriptor));
723
1168
  if (name == NULL) {
724
1169
  rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
725
1170
  }
@@ -727,37 +1172,8 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
727
1172
  klass = rb_define_class_id(
728
1173
  // Docs say this parameter is ignored. User will assign return value to
729
1174
  // their own toplevel constant class name.
730
- rb_intern("Message"),
731
- rb_cObject);
1175
+ rb_intern("Message"), cAbstractMessage);
732
1176
  rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
733
- rb_define_alloc_func(klass, Message_alloc);
734
- rb_require("google/protobuf/message_exts");
735
- rb_include_module(klass, rb_eval_string("::Google::Protobuf::MessageExts"));
736
- rb_extend_object(
737
- klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
738
-
739
- rb_define_method(klass, "method_missing",
740
- Message_method_missing, -1);
741
- rb_define_method(klass, "respond_to_missing?",
742
- Message_respond_to_missing, -1);
743
- rb_define_method(klass, "initialize", Message_initialize, -1);
744
- rb_define_method(klass, "dup", Message_dup, 0);
745
- // Also define #clone so that we don't inherit Object#clone.
746
- rb_define_method(klass, "clone", Message_dup, 0);
747
- rb_define_method(klass, "==", Message_eq, 1);
748
- rb_define_method(klass, "eql?", Message_eq, 1);
749
- rb_define_method(klass, "hash", Message_hash, 0);
750
- rb_define_method(klass, "to_h", Message_to_h, 0);
751
- rb_define_method(klass, "inspect", Message_inspect, 0);
752
- rb_define_method(klass, "to_s", Message_inspect, 0);
753
- rb_define_method(klass, "[]", Message_index, 1);
754
- rb_define_method(klass, "[]=", Message_index_set, 2);
755
- rb_define_singleton_method(klass, "decode", Message_decode, 1);
756
- rb_define_singleton_method(klass, "encode", Message_encode, 1);
757
- rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
758
- rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
759
- rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
760
-
761
1177
  return klass;
762
1178
  }
763
1179
 
@@ -768,16 +1184,15 @@ VALUE build_class_from_descriptor(VALUE descriptor) {
768
1184
  * This module method, provided on each generated enum module, looks up an enum
769
1185
  * value by number and returns its name as a Ruby symbol, or nil if not found.
770
1186
  */
771
- VALUE enum_lookup(VALUE self, VALUE number) {
1187
+ static VALUE enum_lookup(VALUE self, VALUE number) {
772
1188
  int32_t num = NUM2INT(number);
773
1189
  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
774
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
775
-
776
- const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
777
- if (name == NULL) {
778
- return Qnil;
1190
+ const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
1191
+ const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, num);
1192
+ if (ev) {
1193
+ return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
779
1194
  } else {
780
- return ID2SYM(rb_intern(name));
1195
+ return Qnil;
781
1196
  }
782
1197
  }
783
1198
 
@@ -788,17 +1203,15 @@ VALUE enum_lookup(VALUE self, VALUE number) {
788
1203
  * This module method, provided on each generated enum module, looks up an enum
789
1204
  * value by name (as a Ruby symbol) and returns its name, or nil if not found.
790
1205
  */
791
- VALUE enum_resolve(VALUE self, VALUE sym) {
1206
+ static VALUE enum_resolve(VALUE self, VALUE sym) {
792
1207
  const char* name = rb_id2name(SYM2ID(sym));
793
1208
  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
794
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
795
-
796
- int32_t num = 0;
797
- bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
798
- if (!found) {
799
- return Qnil;
1209
+ const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
1210
+ const upb_EnumValueDef* ev = upb_EnumDef_FindValueByName(e, name);
1211
+ if (ev) {
1212
+ return INT2NUM(upb_EnumValueDef_Number(ev));
800
1213
  } else {
801
- return INT2NUM(num);
1214
+ return Qnil;
802
1215
  }
803
1216
  }
804
1217
 
@@ -809,27 +1222,33 @@ VALUE enum_resolve(VALUE self, VALUE sym) {
809
1222
  * This module method, provided on each generated enum module, returns the
810
1223
  * EnumDescriptor corresponding to this enum type.
811
1224
  */
812
- VALUE enum_descriptor(VALUE self) {
1225
+ static VALUE enum_descriptor(VALUE self) {
813
1226
  return rb_ivar_get(self, descriptor_instancevar_interned);
814
1227
  }
815
1228
 
816
1229
  VALUE build_module_from_enumdesc(VALUE _enumdesc) {
817
- EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(_enumdesc);
818
- VALUE mod = rb_define_module_id(
819
- rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
820
-
821
- upb_enum_iter it;
822
- for (upb_enum_begin(&it, enumdesc->enumdef);
823
- !upb_enum_done(&it);
824
- upb_enum_next(&it)) {
825
- const char* name = upb_enum_iter_name(&it);
826
- int32_t value = upb_enum_iter_number(&it);
1230
+ const upb_EnumDef* e = EnumDescriptor_GetEnumDef(_enumdesc);
1231
+ VALUE mod = rb_define_module_id(rb_intern(upb_EnumDef_FullName(e)));
1232
+
1233
+ int n = upb_EnumDef_ValueCount(e);
1234
+ for (int i = 0; i < n; i++) {
1235
+ const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
1236
+ upb_Arena* arena = upb_Arena_New();
1237
+ const char* src_name = upb_EnumValueDef_Name(ev);
1238
+ char* name = upb_strdup2(src_name, strlen(src_name), arena);
1239
+ int32_t value = upb_EnumValueDef_Number(ev);
827
1240
  if (name[0] < 'A' || name[0] > 'Z') {
828
- rb_warn("Enum value '%s' does not start with an uppercase letter "
829
- "as is required for Ruby constants.",
830
- name);
1241
+ if (name[0] >= 'a' && name[0] <= 'z') {
1242
+ name[0] -= 32; // auto capitalize
1243
+ } else {
1244
+ rb_warn(
1245
+ "Enum value '%s' does not start with an uppercase letter "
1246
+ "as is required for Ruby constants.",
1247
+ name);
1248
+ }
831
1249
  }
832
1250
  rb_define_const(mod, name, INT2NUM(value));
1251
+ upb_Arena_Free(arena);
833
1252
  }
834
1253
 
835
1254
  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
@@ -840,20 +1259,132 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
840
1259
  return mod;
841
1260
  }
842
1261
 
843
- /*
844
- * call-seq:
845
- * Google::Protobuf.deep_copy(obj) => copy_of_obj
846
- *
847
- * Performs a deep copy of a RepeatedField instance, a Map instance, or a
848
- * message object, recursively copying its members.
849
- */
850
- VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
851
- VALUE klass = CLASS_OF(obj);
852
- if (klass == cRepeatedField) {
853
- return RepeatedField_deep_copy(obj);
854
- } else if (klass == cMap) {
855
- return Map_deep_copy(obj);
856
- } else {
857
- return Message_deep_copy(obj);
1262
+ // Internal to the library; used by Google::Protobuf.deep_copy.
1263
+ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1264
+ upb_Arena* arena) {
1265
+ // Serialize and parse.
1266
+ upb_Arena* tmp_arena = upb_Arena_New();
1267
+ const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1268
+ size_t size;
1269
+
1270
+ upb_Message* new_msg = upb_Message_New(layout, arena);
1271
+ char* data;
1272
+
1273
+ const upb_FileDef* file = upb_MessageDef_File(m);
1274
+ const upb_ExtensionRegistry* extreg =
1275
+ upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1276
+ if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1277
+ kUpb_EncodeStatus_Ok ||
1278
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1279
+ kUpb_DecodeStatus_Ok) {
1280
+ upb_Arena_Free(tmp_arena);
1281
+ rb_raise(cParseError, "Error occurred copying proto");
858
1282
  }
1283
+
1284
+ upb_Arena_Free(tmp_arena);
1285
+ return new_msg;
1286
+ }
1287
+
1288
+ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1289
+ const char* name, upb_Arena* arena) {
1290
+ if (value == Qnil) {
1291
+ rb_raise(cTypeError, "nil message not allowed here.");
1292
+ }
1293
+
1294
+ VALUE klass = CLASS_OF(value);
1295
+ VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned);
1296
+ const upb_MessageDef* val_m =
1297
+ desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb);
1298
+
1299
+ if (val_m != m) {
1300
+ // Check for possible implicit conversions
1301
+ // TODO: hash conversion?
1302
+
1303
+ switch (upb_MessageDef_WellKnownType(m)) {
1304
+ case kUpb_WellKnown_Timestamp: {
1305
+ // Time -> Google::Protobuf::Timestamp
1306
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1307
+ upb_Message* msg = upb_Message_New(t, arena);
1308
+ upb_MessageValue sec, nsec;
1309
+ struct timespec time;
1310
+ const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1311
+ const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
1312
+
1313
+ if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype;
1314
+
1315
+ time = rb_time_timespec(value);
1316
+ sec.int64_val = time.tv_sec;
1317
+ nsec.int32_val = time.tv_nsec;
1318
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1319
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1320
+ return msg;
1321
+ }
1322
+ case kUpb_WellKnown_Duration: {
1323
+ // Numeric -> Google::Protobuf::Duration
1324
+ const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
1325
+ upb_Message* msg = upb_Message_New(t, arena);
1326
+ upb_MessageValue sec, nsec;
1327
+ const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
1328
+ const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
1329
+
1330
+ if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype;
1331
+
1332
+ sec.int64_val = NUM2LL(value);
1333
+ nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
1334
+ upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1335
+ upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1336
+ return msg;
1337
+ }
1338
+ default:
1339
+ badtype:
1340
+ rb_raise(cTypeError,
1341
+ "Invalid type %s to assign to submessage field '%s'.",
1342
+ rb_class2name(CLASS_OF(value)), name);
1343
+ }
1344
+ }
1345
+
1346
+ Message* self = ruby_to_Message(value);
1347
+ Arena_fuse(self->arena, arena);
1348
+
1349
+ return self->msg;
1350
+ }
1351
+
1352
+ static void Message_define_class(VALUE klass) {
1353
+ rb_define_alloc_func(klass, Message_alloc);
1354
+
1355
+ rb_require("google/protobuf/message_exts");
1356
+ rb_define_method(klass, "method_missing", Message_method_missing, -1);
1357
+ rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
1358
+ -1);
1359
+ rb_define_method(klass, "initialize", Message_initialize, -1);
1360
+ rb_define_method(klass, "dup", Message_dup, 0);
1361
+ // Also define #clone so that we don't inherit Object#clone.
1362
+ rb_define_method(klass, "clone", Message_dup, 0);
1363
+ rb_define_method(klass, "==", Message_eq, 1);
1364
+ rb_define_method(klass, "eql?", Message_eq, 1);
1365
+ rb_define_method(klass, "freeze", Message_freeze, 0);
1366
+ rb_define_method(klass, "hash", Message_hash, 0);
1367
+ rb_define_method(klass, "to_h", Message_to_h, 0);
1368
+ rb_define_method(klass, "inspect", Message_inspect, 0);
1369
+ rb_define_method(klass, "to_s", Message_inspect, 0);
1370
+ rb_define_method(klass, "[]", Message_index, 1);
1371
+ rb_define_method(klass, "[]=", Message_index_set, 2);
1372
+ rb_define_singleton_method(klass, "decode", Message_decode, -1);
1373
+ rb_define_singleton_method(klass, "encode", Message_encode, -1);
1374
+ rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
1375
+ rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
1376
+ rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
1377
+ }
1378
+
1379
+ void Message_register(VALUE protobuf) {
1380
+ cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
1381
+ cAbstractMessage =
1382
+ rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
1383
+ Message_define_class(cAbstractMessage);
1384
+ rb_gc_register_address(&cAbstractMessage);
1385
+
1386
+ // Ruby-interned string: "descriptor". We use this identifier to store an
1387
+ // instance variable on message classes we create in order to link them back
1388
+ // to their descriptors.
1389
+ descriptor_instancevar_interned = rb_intern("@descriptor");
859
1390
  }