google-protobuf 3.5.0 → 3.23.4

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

Potentially problematic release.


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

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