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