Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: third_party/protobuf/ruby/ext/google/protobuf_c/message.c

Issue 1322483002: Revert https://codereview.chromium.org/1291903002 (protobuf roll). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include "protobuf.h"
32
33 // -----------------------------------------------------------------------------
34 // Class/module creation from msgdefs and enumdefs, respectively.
35 // -----------------------------------------------------------------------------
36
37 void* Message_data(void* msg) {
38 return ((uint8_t *)msg) + sizeof(MessageHeader);
39 }
40
41 void Message_mark(void* _self) {
42 MessageHeader* self = (MessageHeader *)_self;
43 layout_mark(self->descriptor->layout, Message_data(self));
44 }
45
46 void Message_free(void* self) {
47 xfree(self);
48 }
49
50 rb_data_type_t Message_type = {
51 "Message",
52 { Message_mark, Message_free, NULL },
53 };
54
55 VALUE Message_alloc(VALUE klass) {
56 VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
57 Descriptor* desc = ruby_to_Descriptor(descriptor);
58 MessageHeader* msg = (MessageHeader*)ALLOC_N(
59 uint8_t, sizeof(MessageHeader) + desc->layout->size);
60 memset(Message_data(msg), 0, desc->layout->size);
61
62 // We wrap first so that everything in the message object is GC-rooted in case
63 // a collection happens during object creation in layout_init().
64 VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
65 msg->descriptor = desc;
66 rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
67
68 layout_init(desc->layout, Message_data(msg));
69
70 return ret;
71 }
72
73 static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
74 // If no fields in the oneof, always nil.
75 if (upb_oneofdef_numfields(o) == 0) {
76 return Qnil;
77 }
78 // Grab the first field in the oneof so we can get its layout info to find the
79 // oneof_case field.
80 upb_oneof_iter it;
81 upb_oneof_begin(&it, o);
82 assert(!upb_oneof_done(&it));
83 const upb_fielddef* first_field = upb_oneof_iter_field(&it);
84 assert(upb_fielddef_containingoneof(first_field) != NULL);
85
86 size_t case_ofs =
87 self->descriptor->layout->
88 fields[upb_fielddef_index(first_field)].case_offset;
89 uint32_t oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
90
91 if (oneof_case == ONEOF_CASE_NONE) {
92 return Qnil;
93 }
94
95 // oneof_case is a field index, so find that field.
96 const upb_fielddef* f = upb_oneofdef_itof(o, oneof_case);
97 assert(f != NULL);
98
99 return ID2SYM(rb_intern(upb_fielddef_name(f)));
100 }
101
102 /*
103 * call-seq:
104 * Message.method_missing(*args)
105 *
106 * Provides accessors and setters for message fields according to their field
107 * names. For any field whose name does not conflict with a built-in method, an
108 * accessor is provided with the same name as the field, and a setter is
109 * provided with the name of the field plus the '=' suffix. Thus, given a
110 * message instance 'msg' with field 'foo', the following code is valid:
111 *
112 * msg.foo = 42
113 * puts msg.foo
114 *
115 * This method also provides read-only accessors for oneofs. If a oneof exists
116 * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
117 * the name of the field in that oneof that is currently set, or nil if none.
118 */
119 VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
120 MessageHeader* self;
121 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
122 if (argc < 1) {
123 rb_raise(rb_eArgError, "Expected method name as first argument.");
124 }
125 VALUE method_name = argv[0];
126 if (!SYMBOL_P(method_name)) {
127 rb_raise(rb_eArgError, "Expected symbol as method name.");
128 }
129 VALUE method_str = rb_id2str(SYM2ID(method_name));
130 char* name = RSTRING_PTR(method_str);
131 size_t name_len = RSTRING_LEN(method_str);
132 bool setter = false;
133
134 // Setters have names that end in '='.
135 if (name[name_len - 1] == '=') {
136 setter = true;
137 name_len--;
138 }
139
140 // Check for a oneof name first.
141 const upb_oneofdef* o = upb_msgdef_ntoo(self->descriptor->msgdef,
142 name, name_len);
143 if (o != NULL) {
144 if (setter) {
145 rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
146 }
147 return which_oneof_field(self, o);
148 }
149
150 // Otherwise, check for a field with that name.
151 const upb_fielddef* f = upb_msgdef_ntof(self->descriptor->msgdef,
152 name, name_len);
153
154 if (f == NULL) {
155 rb_raise(rb_eArgError, "Unknown field");
156 }
157
158 if (setter) {
159 if (argc < 2) {
160 rb_raise(rb_eArgError, "No value provided to setter.");
161 }
162 layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
163 return Qnil;
164 } else {
165 return layout_get(self->descriptor->layout, Message_data(self), f);
166 }
167 }
168
169 int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
170 MessageHeader* self;
171 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
172
173 if (!SYMBOL_P(key)) {
174 rb_raise(rb_eArgError,
175 "Expected symbols as hash keys in initialization map.");
176 }
177
178 VALUE method_str = rb_id2str(SYM2ID(key));
179 char* name = RSTRING_PTR(method_str);
180 const upb_fielddef* f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
181 if (f == NULL) {
182 rb_raise(rb_eArgError,
183 "Unknown field name in initialization map entry.");
184 }
185
186 if (is_map_field(f)) {
187 if (TYPE(val) != T_HASH) {
188 rb_raise(rb_eArgError,
189 "Expected Hash object as initializer value for map field.");
190 }
191 VALUE map = layout_get(self->descriptor->layout, Message_data(self), f);
192 Map_merge_into_self(map, val);
193 } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
194 if (TYPE(val) != T_ARRAY) {
195 rb_raise(rb_eArgError,
196 "Expected array as initializer value for repeated field.");
197 }
198 VALUE ary = layout_get(self->descriptor->layout, Message_data(self), f);
199 for (int i = 0; i < RARRAY_LEN(val); i++) {
200 RepeatedField_push(ary, rb_ary_entry(val, i));
201 }
202 } else {
203 layout_set(self->descriptor->layout, Message_data(self), f, val);
204 }
205 return 0;
206 }
207
208 /*
209 * call-seq:
210 * Message.new(kwargs) => new_message
211 *
212 * Creates a new instance of the given message class. Keyword arguments may be
213 * provided with keywords corresponding to field names.
214 *
215 * Note that no literal Message class exists. Only concrete classes per message
216 * type exist, as provided by the #msgclass method on Descriptors after they
217 * have been added to a pool. The method definitions described here on the
218 * Message class are provided on each concrete message class.
219 */
220 VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
221 if (argc == 0) {
222 return Qnil;
223 }
224 if (argc != 1) {
225 rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
226 }
227 VALUE hash_args = argv[0];
228 if (TYPE(hash_args) != T_HASH) {
229 rb_raise(rb_eArgError, "Expected hash arguments.");
230 }
231
232 rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
233 return Qnil;
234 }
235
236 /*
237 * call-seq:
238 * Message.dup => new_message
239 *
240 * Performs a shallow copy of this message and returns the new copy.
241 */
242 VALUE Message_dup(VALUE _self) {
243 MessageHeader* self;
244 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
245
246 VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
247 MessageHeader* new_msg_self;
248 TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
249
250 layout_dup(self->descriptor->layout,
251 Message_data(new_msg_self),
252 Message_data(self));
253
254 return new_msg;
255 }
256
257 // Internal only; used by Google::Protobuf.deep_copy.
258 VALUE Message_deep_copy(VALUE _self) {
259 MessageHeader* self;
260 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
261
262 VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
263 MessageHeader* new_msg_self;
264 TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
265
266 layout_deep_copy(self->descriptor->layout,
267 Message_data(new_msg_self),
268 Message_data(self));
269
270 return new_msg;
271 }
272
273 /*
274 * call-seq:
275 * Message.==(other) => boolean
276 *
277 * Performs a deep comparison of this message with another. Messages are equal
278 * if they have the same type and if each field is equal according to the :==
279 * method's semantics (a more efficient comparison may actually be done if the
280 * field is of a primitive type).
281 */
282 VALUE Message_eq(VALUE _self, VALUE _other) {
283 MessageHeader* self;
284 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
285
286 MessageHeader* other;
287 TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
288
289 if (self->descriptor != other->descriptor) {
290 return Qfalse;
291 }
292
293 return layout_eq(self->descriptor->layout,
294 Message_data(self),
295 Message_data(other));
296 }
297
298 /*
299 * call-seq:
300 * Message.hash => hash_value
301 *
302 * Returns a hash value that represents this message's field values.
303 */
304 VALUE Message_hash(VALUE _self) {
305 MessageHeader* self;
306 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
307
308 return layout_hash(self->descriptor->layout, Message_data(self));
309 }
310
311 /*
312 * call-seq:
313 * Message.inspect => string
314 *
315 * Returns a human-readable string representing this message. It will be
316 * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
317 * field's value is represented according to its own #inspect method.
318 */
319 VALUE Message_inspect(VALUE _self) {
320 MessageHeader* self;
321 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
322
323 VALUE str = rb_str_new2("<");
324 str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
325 str = rb_str_cat2(str, ": ");
326 str = rb_str_append(str, layout_inspect(
327 self->descriptor->layout, Message_data(self)));
328 str = rb_str_cat2(str, ">");
329 return str;
330 }
331
332
333 VALUE Message_to_h(VALUE _self) {
334 MessageHeader* self;
335 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
336
337 VALUE hash = rb_hash_new();
338
339 upb_msg_field_iter it;
340 for (upb_msg_field_begin(&it, self->descriptor->msgdef);
341 !upb_msg_field_done(&it);
342 upb_msg_field_next(&it)) {
343 const upb_fielddef* field = upb_msg_iter_field(&it);
344 VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
345 field);
346 VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
347 if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
348 msg_value = RepeatedField_to_ary(msg_value);
349 }
350 rb_hash_aset(hash, msg_key, msg_value);
351 }
352 return hash;
353 }
354
355
356
357 /*
358 * call-seq:
359 * Message.[](index) => value
360 *
361 * Accesses a field's value by field name. The provided field name should be a
362 * string.
363 */
364 VALUE Message_index(VALUE _self, VALUE field_name) {
365 MessageHeader* self;
366 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
367 Check_Type(field_name, T_STRING);
368 const upb_fielddef* field =
369 upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
370 if (field == NULL) {
371 return Qnil;
372 }
373 return layout_get(self->descriptor->layout, Message_data(self), field);
374 }
375
376 /*
377 * call-seq:
378 * Message.[]=(index, value)
379 *
380 * Sets a field's value by field name. The provided field name should be a
381 * string.
382 */
383 VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
384 MessageHeader* self;
385 TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
386 Check_Type(field_name, T_STRING);
387 const upb_fielddef* field =
388 upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
389 if (field == NULL) {
390 rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
391 }
392 layout_set(self->descriptor->layout, Message_data(self), field, value);
393 return Qnil;
394 }
395
396 /*
397 * call-seq:
398 * Message.descriptor => descriptor
399 *
400 * Class method that returns the Descriptor instance corresponding to this
401 * message class's type.
402 */
403 VALUE Message_descriptor(VALUE klass) {
404 return rb_ivar_get(klass, descriptor_instancevar_interned);
405 }
406
407 VALUE build_class_from_descriptor(Descriptor* desc) {
408 if (desc->layout == NULL) {
409 desc->layout = create_layout(desc->msgdef);
410 }
411 if (desc->fill_method == NULL) {
412 desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
413 }
414
415 const char* name = upb_msgdef_fullname(desc->msgdef);
416 if (name == NULL) {
417 rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
418 }
419
420 VALUE klass = rb_define_class_id(
421 // Docs say this parameter is ignored. User will assign return value to
422 // their own toplevel constant class name.
423 rb_intern("Message"),
424 rb_cObject);
425 rb_ivar_set(klass, descriptor_instancevar_interned,
426 get_def_obj(desc->msgdef));
427 rb_define_alloc_func(klass, Message_alloc);
428 rb_require("google/protobuf/message_exts");
429 rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
430 rb_extend_object(
431 klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
432
433 rb_define_method(klass, "method_missing",
434 Message_method_missing, -1);
435 rb_define_method(klass, "initialize", Message_initialize, -1);
436 rb_define_method(klass, "dup", Message_dup, 0);
437 // Also define #clone so that we don't inherit Object#clone.
438 rb_define_method(klass, "clone", Message_dup, 0);
439 rb_define_method(klass, "==", Message_eq, 1);
440 rb_define_method(klass, "hash", Message_hash, 0);
441 rb_define_method(klass, "to_h", Message_to_h, 0);
442 rb_define_method(klass, "to_hash", Message_to_h, 0);
443 rb_define_method(klass, "inspect", Message_inspect, 0);
444 rb_define_method(klass, "[]", Message_index, 1);
445 rb_define_method(klass, "[]=", Message_index_set, 2);
446 rb_define_singleton_method(klass, "decode", Message_decode, 1);
447 rb_define_singleton_method(klass, "encode", Message_encode, 1);
448 rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
449 rb_define_singleton_method(klass, "encode_json", Message_encode_json, 1);
450 rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
451
452 return klass;
453 }
454
455 /*
456 * call-seq:
457 * Enum.lookup(number) => name
458 *
459 * This module method, provided on each generated enum module, looks up an enum
460 * value by number and returns its name as a Ruby symbol, or nil if not found.
461 */
462 VALUE enum_lookup(VALUE self, VALUE number) {
463 int32_t num = NUM2INT(number);
464 VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
465 EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
466
467 const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
468 if (name == NULL) {
469 return Qnil;
470 } else {
471 return ID2SYM(rb_intern(name));
472 }
473 }
474
475 /*
476 * call-seq:
477 * Enum.resolve(name) => number
478 *
479 * This module method, provided on each generated enum module, looks up an enum
480 * value by name (as a Ruby symbol) and returns its name, or nil if not found.
481 */
482 VALUE enum_resolve(VALUE self, VALUE sym) {
483 const char* name = rb_id2name(SYM2ID(sym));
484 VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
485 EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
486
487 int32_t num = 0;
488 bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
489 if (!found) {
490 return Qnil;
491 } else {
492 return INT2NUM(num);
493 }
494 }
495
496 /*
497 * call-seq:
498 * Enum.descriptor
499 *
500 * This module method, provided on each generated enum module, returns the
501 * EnumDescriptor corresponding to this enum type.
502 */
503 VALUE enum_descriptor(VALUE self) {
504 return rb_ivar_get(self, descriptor_instancevar_interned);
505 }
506
507 VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
508 VALUE mod = rb_define_module_id(
509 rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
510
511 upb_enum_iter it;
512 for (upb_enum_begin(&it, enumdesc->enumdef);
513 !upb_enum_done(&it);
514 upb_enum_next(&it)) {
515 const char* name = upb_enum_iter_name(&it);
516 int32_t value = upb_enum_iter_number(&it);
517 if (name[0] < 'A' || name[0] > 'Z') {
518 rb_raise(rb_eTypeError,
519 "Enum value '%s' does not start with an uppercase letter "
520 "as is required for Ruby constants.",
521 name);
522 }
523 rb_define_const(mod, name, INT2NUM(value));
524 }
525
526 rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
527 rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
528 rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
529 rb_ivar_set(mod, descriptor_instancevar_interned,
530 get_def_obj(enumdesc->enumdef));
531
532 return mod;
533 }
534
535 /*
536 * call-seq:
537 * Google::Protobuf.deep_copy(obj) => copy_of_obj
538 *
539 * Performs a deep copy of a RepeatedField instance, a Map instance, or a
540 * message object, recursively copying its members.
541 */
542 VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
543 VALUE klass = CLASS_OF(obj);
544 if (klass == cRepeatedField) {
545 return RepeatedField_deep_copy(obj);
546 } else if (klass == cMap) {
547 return Map_deep_copy(obj);
548 } else {
549 return Message_deep_copy(obj);
550 }
551 }
OLDNEW
« no previous file with comments | « third_party/protobuf/ruby/ext/google/protobuf_c/map.c ('k') | third_party/protobuf/ruby/ext/google/protobuf_c/protobuf.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698