google-protobuf 3.19.0.rc.1-x86_64-darwin

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/ext/google/protobuf_c/convert.c +348 -0
  3. data/ext/google/protobuf_c/convert.h +72 -0
  4. data/ext/google/protobuf_c/defs.c +1284 -0
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +20 -0
  7. data/ext/google/protobuf_c/map.c +694 -0
  8. data/ext/google/protobuf_c/map.h +67 -0
  9. data/ext/google/protobuf_c/message.c +1328 -0
  10. data/ext/google/protobuf_c/message.h +101 -0
  11. data/ext/google/protobuf_c/protobuf.c +470 -0
  12. data/ext/google/protobuf_c/protobuf.h +117 -0
  13. data/ext/google/protobuf_c/repeated_field.c +659 -0
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +9171 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +4704 -0
  17. data/ext/google/protobuf_c/wrap_memcpy.c +51 -0
  18. data/lib/google/2.3/protobuf_c.bundle +0 -0
  19. data/lib/google/2.4/protobuf_c.bundle +0 -0
  20. data/lib/google/2.5/protobuf_c.bundle +0 -0
  21. data/lib/google/2.6/protobuf_c.bundle +0 -0
  22. data/lib/google/2.7/protobuf_c.bundle +0 -0
  23. data/lib/google/3.0/protobuf_c.bundle +0 -0
  24. data/lib/google/protobuf/any_pb.rb +19 -0
  25. data/lib/google/protobuf/api_pb.rb +41 -0
  26. data/lib/google/protobuf/descriptor_dsl.rb +458 -0
  27. data/lib/google/protobuf/descriptor_pb.rb +266 -0
  28. data/lib/google/protobuf/duration_pb.rb +19 -0
  29. data/lib/google/protobuf/empty_pb.rb +17 -0
  30. data/lib/google/protobuf/field_mask_pb.rb +18 -0
  31. data/lib/google/protobuf/message_exts.rb +53 -0
  32. data/lib/google/protobuf/repeated_field.rb +188 -0
  33. data/lib/google/protobuf/source_context_pb.rb +18 -0
  34. data/lib/google/protobuf/struct_pb.rb +37 -0
  35. data/lib/google/protobuf/timestamp_pb.rb +19 -0
  36. data/lib/google/protobuf/type_pb.rb +91 -0
  37. data/lib/google/protobuf/well_known_types.rb +235 -0
  38. data/lib/google/protobuf/wrappers_pb.rb +50 -0
  39. data/lib/google/protobuf.rb +79 -0
  40. data/tests/basic.rb +640 -0
  41. data/tests/generated_code_test.rb +23 -0
  42. data/tests/stress.rb +38 -0
  43. metadata +144 -0
@@ -0,0 +1,694 @@
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 "convert.h"
32
+ #include "defs.h"
33
+ #include "message.h"
34
+ #include "protobuf.h"
35
+
36
+ // -----------------------------------------------------------------------------
37
+ // Basic map operations on top of upb_map.
38
+ //
39
+ // Note that we roll our own `Map` container here because, as for
40
+ // `RepeatedField`, we want a strongly-typed container. This is so that any user
41
+ // errors due to incorrect map key or value types are raised as close as
42
+ // possible to the error site, rather than at some deferred point (e.g.,
43
+ // serialization).
44
+ // -----------------------------------------------------------------------------
45
+
46
+ // -----------------------------------------------------------------------------
47
+ // Map container type.
48
+ // -----------------------------------------------------------------------------
49
+
50
+ typedef struct {
51
+ const upb_map *map; // Can convert to mutable when non-frozen.
52
+ upb_fieldtype_t key_type;
53
+ TypeInfo value_type_info;
54
+ VALUE value_type_class;
55
+ VALUE arena;
56
+ } Map;
57
+
58
+ static void Map_mark(void* _self) {
59
+ Map* self = _self;
60
+ rb_gc_mark(self->value_type_class);
61
+ rb_gc_mark(self->arena);
62
+ }
63
+
64
+ const rb_data_type_t Map_type = {
65
+ "Google::Protobuf::Map",
66
+ { Map_mark, RUBY_DEFAULT_FREE, NULL },
67
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
68
+ };
69
+
70
+ VALUE cMap;
71
+
72
+ static Map* ruby_to_Map(VALUE _self) {
73
+ Map* self;
74
+ TypedData_Get_Struct(_self, Map, &Map_type, self);
75
+ return self;
76
+ }
77
+
78
+ static VALUE Map_alloc(VALUE klass) {
79
+ Map* self = ALLOC(Map);
80
+ self->map = NULL;
81
+ self->value_type_class = Qnil;
82
+ self->value_type_info.def.msgdef = NULL;
83
+ self->arena = Qnil;
84
+ return TypedData_Wrap_Struct(klass, &Map_type, self);
85
+ }
86
+
87
+ VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
88
+ TypeInfo value_type, VALUE arena) {
89
+ PBRUBY_ASSERT(map);
90
+
91
+ VALUE val = ObjectCache_Get(map);
92
+
93
+ if (val == Qnil) {
94
+ val = Map_alloc(cMap);
95
+ Map* self;
96
+ ObjectCache_Add(map, val);
97
+ TypedData_Get_Struct(val, Map, &Map_type, self);
98
+ self->map = map;
99
+ self->arena = arena;
100
+ self->key_type = key_type;
101
+ self->value_type_info = value_type;
102
+ if (self->value_type_info.type == UPB_TYPE_MESSAGE) {
103
+ const upb_msgdef *val_m = self->value_type_info.def.msgdef;
104
+ self->value_type_class = Descriptor_DefToClass(val_m);
105
+ }
106
+ }
107
+
108
+ return val;
109
+ }
110
+
111
+ static VALUE Map_new_this_type(Map *from) {
112
+ VALUE arena_rb = Arena_new();
113
+ upb_map* map = upb_map_new(Arena_get(arena_rb), from->key_type,
114
+ from->value_type_info.type);
115
+ VALUE ret =
116
+ Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
117
+ PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class);
118
+ return ret;
119
+ }
120
+
121
+ static TypeInfo Map_keyinfo(Map* self) {
122
+ TypeInfo ret;
123
+ ret.type = self->key_type;
124
+ ret.def.msgdef = NULL;
125
+ return ret;
126
+ }
127
+
128
+ static upb_map *Map_GetMutable(VALUE _self) {
129
+ rb_check_frozen(_self);
130
+ return (upb_map*)ruby_to_Map(_self)->map;
131
+ }
132
+
133
+ VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
134
+ TypeInfo val_info) {
135
+ VALUE hash = rb_hash_new();
136
+ size_t iter = UPB_MAP_BEGIN;
137
+ TypeInfo key_info = TypeInfo_from_type(key_type);
138
+
139
+ if (!map) return hash;
140
+
141
+ while (upb_mapiter_next(map, &iter)) {
142
+ upb_msgval key = upb_mapiter_key(map, iter);
143
+ upb_msgval val = upb_mapiter_value(map, iter);
144
+ VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
145
+ VALUE val_val = Scalar_CreateHash(val, val_info);
146
+ rb_hash_aset(hash, key_val, val_val);
147
+ }
148
+
149
+ return hash;
150
+ }
151
+
152
+ VALUE Map_deep_copy(VALUE obj) {
153
+ Map* self = ruby_to_Map(obj);
154
+ VALUE new_arena_rb = Arena_new();
155
+ upb_arena *arena = Arena_get(new_arena_rb);
156
+ upb_map* new_map =
157
+ upb_map_new(arena, self->key_type, self->value_type_info.type);
158
+ size_t iter = UPB_MAP_BEGIN;
159
+ while (upb_mapiter_next(self->map, &iter)) {
160
+ upb_msgval key = upb_mapiter_key(self->map, iter);
161
+ upb_msgval val = upb_mapiter_value(self->map, iter);
162
+ upb_msgval val_copy = Msgval_DeepCopy(val, self->value_type_info, arena);
163
+ upb_map_set(new_map, key, val_copy, arena);
164
+ }
165
+
166
+ return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
167
+ new_arena_rb);
168
+ }
169
+
170
+ const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
171
+ upb_arena* arena) {
172
+ const upb_fielddef* key_field = map_field_key(field);
173
+ const upb_fielddef* value_field = map_field_value(field);
174
+ TypeInfo value_type_info = TypeInfo_get(value_field);
175
+ Map* self;
176
+
177
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
178
+ RTYPEDDATA_TYPE(val) != &Map_type) {
179
+ rb_raise(cTypeError, "Expected Map instance");
180
+ }
181
+
182
+ self = ruby_to_Map(val);
183
+ if (self->key_type != upb_fielddef_type(key_field)) {
184
+ rb_raise(cTypeError, "Map key type does not match field's key type");
185
+ }
186
+ if (self->value_type_info.type != value_type_info.type) {
187
+ rb_raise(cTypeError, "Map value type does not match field's value type");
188
+ }
189
+ if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
190
+ rb_raise(cTypeError, "Map value type has wrong message/enum class");
191
+ }
192
+
193
+ Arena_fuse(self->arena, arena);
194
+ return self->map;
195
+ }
196
+
197
+ void Map_Inspect(StringBuilder* b, const upb_map* map, upb_fieldtype_t key_type,
198
+ TypeInfo val_type) {
199
+ bool first = true;
200
+ TypeInfo key_type_info = {key_type};
201
+ StringBuilder_Printf(b, "{");
202
+ if (map) {
203
+ size_t iter = UPB_MAP_BEGIN;
204
+ while (upb_mapiter_next(map, &iter)) {
205
+ upb_msgval key = upb_mapiter_key(map, iter);
206
+ upb_msgval val = upb_mapiter_value(map, iter);
207
+ if (first) {
208
+ first = false;
209
+ } else {
210
+ StringBuilder_Printf(b, ", ");
211
+ }
212
+ StringBuilder_PrintMsgval(b, key, key_type_info);
213
+ StringBuilder_Printf(b, "=>");
214
+ StringBuilder_PrintMsgval(b, val, val_type);
215
+ }
216
+ }
217
+ StringBuilder_Printf(b, "}");
218
+ }
219
+
220
+ static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
221
+ Map* self = ruby_to_Map(_self);
222
+ upb_arena *arena = Arena_get(self->arena);
223
+ upb_msgval key_val = Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
224
+ upb_msgval val_val = Convert_RubyToUpb(val, "", self->value_type_info, arena);
225
+ upb_map_set(Map_GetMutable(_self), key_val, val_val, arena);
226
+ return ST_CONTINUE;
227
+ }
228
+
229
+ // Used only internally -- shared by #merge and #initialize.
230
+ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
231
+ if (TYPE(hashmap) == T_HASH) {
232
+ rb_hash_foreach(hashmap, merge_into_self_callback, _self);
233
+ } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
234
+ RTYPEDDATA_TYPE(hashmap) == &Map_type) {
235
+ Map* self = ruby_to_Map(_self);
236
+ Map* other = ruby_to_Map(hashmap);
237
+ upb_arena *arena = Arena_get(self->arena);
238
+ upb_msg *self_msg = Map_GetMutable(_self);
239
+ size_t iter = UPB_MAP_BEGIN;
240
+
241
+ Arena_fuse(other->arena, arena);
242
+
243
+ if (self->key_type != other->key_type ||
244
+ self->value_type_info.type != other->value_type_info.type ||
245
+ self->value_type_class != other->value_type_class) {
246
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
247
+ }
248
+
249
+ while (upb_mapiter_next(other->map, &iter)) {
250
+ upb_msgval key = upb_mapiter_key(other->map, iter);
251
+ upb_msgval val = upb_mapiter_value(other->map, iter);
252
+ upb_map_set(self_msg, key, val, arena);
253
+ }
254
+ } else {
255
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
256
+ }
257
+ return _self;
258
+ }
259
+
260
+ /*
261
+ * call-seq:
262
+ * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
263
+ * => new map
264
+ *
265
+ * Allocates a new Map container. This constructor may be called with 2, 3, or 4
266
+ * arguments. The first two arguments are always present and are symbols (taking
267
+ * on the same values as field-type symbols in message descriptors) that
268
+ * indicate the type of the map key and value fields.
269
+ *
270
+ * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
271
+ * :string, :bytes.
272
+ *
273
+ * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
274
+ * :string, :bytes, :enum, :message.
275
+ *
276
+ * The third argument, value_typeclass, must be present if value_type is :enum
277
+ * or :message. As in RepeatedField#new, this argument must be a message class
278
+ * (for :message) or enum module (for :enum).
279
+ *
280
+ * The last argument, if present, provides initial content for map. Note that
281
+ * this may be an ordinary Ruby hashmap or another Map instance with identical
282
+ * key and value types. Also note that this argument may be present whether or
283
+ * not value_typeclass is present (and it is unambiguously separate from
284
+ * value_typeclass because value_typeclass's presence is strictly determined by
285
+ * value_type). The contents of this initial hashmap or Map instance are
286
+ * shallow-copied into the new Map: the original map is unmodified, but
287
+ * references to underlying objects will be shared if the value type is a
288
+ * message type.
289
+ */
290
+ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
291
+ Map* self = ruby_to_Map(_self);
292
+ VALUE init_arg;
293
+
294
+ // We take either two args (:key_type, :value_type), three args (:key_type,
295
+ // :value_type, "ValueMessageType"), or four args (the above plus an initial
296
+ // hashmap).
297
+ if (argc < 2 || argc > 4) {
298
+ rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments.");
299
+ }
300
+
301
+ self->key_type = ruby_to_fieldtype(argv[0]);
302
+ self->value_type_info =
303
+ TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
304
+ self->arena = Arena_new();
305
+
306
+ // Check that the key type is an allowed type.
307
+ switch (self->key_type) {
308
+ case UPB_TYPE_INT32:
309
+ case UPB_TYPE_INT64:
310
+ case UPB_TYPE_UINT32:
311
+ case UPB_TYPE_UINT64:
312
+ case UPB_TYPE_BOOL:
313
+ case UPB_TYPE_STRING:
314
+ case UPB_TYPE_BYTES:
315
+ // These are OK.
316
+ break;
317
+ default:
318
+ rb_raise(rb_eArgError, "Invalid key type for map.");
319
+ }
320
+
321
+ self->map = upb_map_new(Arena_get(self->arena), self->key_type,
322
+ self->value_type_info.type);
323
+ ObjectCache_Add(self->map, _self);
324
+
325
+ if (init_arg != Qnil) {
326
+ Map_merge_into_self(_self, init_arg);
327
+ }
328
+
329
+ return Qnil;
330
+ }
331
+
332
+ /*
333
+ * call-seq:
334
+ * Map.each(&block)
335
+ *
336
+ * Invokes &block on each |key, value| pair in the map, in unspecified order.
337
+ * Note that Map also includes Enumerable; map thus acts like a normal Ruby
338
+ * sequence.
339
+ */
340
+ static VALUE Map_each(VALUE _self) {
341
+ Map* self = ruby_to_Map(_self);
342
+ size_t iter = UPB_MAP_BEGIN;
343
+
344
+ while (upb_mapiter_next(self->map, &iter)) {
345
+ upb_msgval key = upb_mapiter_key(self->map, iter);
346
+ upb_msgval val = upb_mapiter_value(self->map, iter);
347
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
348
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
349
+ rb_yield_values(2, key_val, val_val);
350
+ }
351
+
352
+ return Qnil;
353
+ }
354
+
355
+ /*
356
+ * call-seq:
357
+ * Map.keys => [list_of_keys]
358
+ *
359
+ * Returns the list of keys contained in the map, in unspecified order.
360
+ */
361
+ static VALUE Map_keys(VALUE _self) {
362
+ Map* self = ruby_to_Map(_self);
363
+ size_t iter = UPB_MAP_BEGIN;
364
+ VALUE ret = rb_ary_new();
365
+
366
+ while (upb_mapiter_next(self->map, &iter)) {
367
+ upb_msgval key = upb_mapiter_key(self->map, iter);
368
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
369
+ rb_ary_push(ret, key_val);
370
+ }
371
+
372
+ return ret;
373
+ }
374
+
375
+ /*
376
+ * call-seq:
377
+ * Map.values => [list_of_values]
378
+ *
379
+ * Returns the list of values contained in the map, in unspecified order.
380
+ */
381
+ static VALUE Map_values(VALUE _self) {
382
+ Map* self = ruby_to_Map(_self);
383
+ size_t iter = UPB_MAP_BEGIN;
384
+ VALUE ret = rb_ary_new();
385
+
386
+ while (upb_mapiter_next(self->map, &iter)) {
387
+ upb_msgval val = upb_mapiter_value(self->map, iter);
388
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
389
+ rb_ary_push(ret, val_val);
390
+ }
391
+
392
+ return ret;
393
+ }
394
+
395
+ /*
396
+ * call-seq:
397
+ * Map.[](key) => value
398
+ *
399
+ * Accesses the element at the given key. Throws an exception if the key type is
400
+ * incorrect. Returns nil when the key is not present in the map.
401
+ */
402
+ static VALUE Map_index(VALUE _self, VALUE key) {
403
+ Map* self = ruby_to_Map(_self);
404
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
405
+ upb_msgval val;
406
+
407
+ if (upb_map_get(self->map, key_upb, &val)) {
408
+ return Convert_UpbToRuby(val, self->value_type_info, self->arena);
409
+ } else {
410
+ return Qnil;
411
+ }
412
+ }
413
+
414
+ /*
415
+ * call-seq:
416
+ * Map.[]=(key, value) => value
417
+ *
418
+ * Inserts or overwrites the value at the given key with the given new value.
419
+ * Throws an exception if the key type is incorrect. Returns the new value that
420
+ * was just inserted.
421
+ */
422
+ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
423
+ Map* self = ruby_to_Map(_self);
424
+ upb_arena *arena = Arena_get(self->arena);
425
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
426
+ upb_msgval val_upb = Convert_RubyToUpb(val, "", self->value_type_info, arena);
427
+
428
+ upb_map_set(Map_GetMutable(_self), key_upb, val_upb, arena);
429
+
430
+ return val;
431
+ }
432
+
433
+ /*
434
+ * call-seq:
435
+ * Map.has_key?(key) => bool
436
+ *
437
+ * Returns true if the given key is present in the map. Throws an exception if
438
+ * the key has the wrong type.
439
+ */
440
+ static VALUE Map_has_key(VALUE _self, VALUE key) {
441
+ Map* self = ruby_to_Map(_self);
442
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
443
+
444
+ if (upb_map_get(self->map, key_upb, NULL)) {
445
+ return Qtrue;
446
+ } else {
447
+ return Qfalse;
448
+ }
449
+ }
450
+
451
+ /*
452
+ * call-seq:
453
+ * Map.delete(key) => old_value
454
+ *
455
+ * Deletes the value at the given key, if any, returning either the old value or
456
+ * nil if none was present. Throws an exception if the key is of the wrong type.
457
+ */
458
+ static VALUE Map_delete(VALUE _self, VALUE key) {
459
+ Map* self = ruby_to_Map(_self);
460
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
461
+ upb_msgval val_upb;
462
+ VALUE ret;
463
+
464
+ rb_check_frozen(_self);
465
+
466
+ // TODO(haberman): make upb_map_delete() also capable of returning the deleted
467
+ // value.
468
+ if (upb_map_get(self->map, key_upb, &val_upb)) {
469
+ ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
470
+ } else {
471
+ ret = Qnil;
472
+ }
473
+
474
+ upb_map_delete(Map_GetMutable(_self), key_upb);
475
+
476
+ return ret;
477
+ }
478
+
479
+ /*
480
+ * call-seq:
481
+ * Map.clear
482
+ *
483
+ * Removes all entries from the map.
484
+ */
485
+ static VALUE Map_clear(VALUE _self) {
486
+ upb_map_clear(Map_GetMutable(_self));
487
+ return Qnil;
488
+ }
489
+
490
+ /*
491
+ * call-seq:
492
+ * Map.length
493
+ *
494
+ * Returns the number of entries (key-value pairs) in the map.
495
+ */
496
+ static VALUE Map_length(VALUE _self) {
497
+ Map* self = ruby_to_Map(_self);
498
+ return ULL2NUM(upb_map_size(self->map));
499
+ }
500
+
501
+ /*
502
+ * call-seq:
503
+ * Map.dup => new_map
504
+ *
505
+ * Duplicates this map with a shallow copy. References to all non-primitive
506
+ * element objects (e.g., submessages) are shared.
507
+ */
508
+ static VALUE Map_dup(VALUE _self) {
509
+ Map* self = ruby_to_Map(_self);
510
+ VALUE new_map_rb = Map_new_this_type(self);
511
+ Map* new_self = ruby_to_Map(new_map_rb);
512
+ size_t iter = UPB_MAP_BEGIN;
513
+ upb_arena *arena = Arena_get(new_self->arena);
514
+ upb_map *new_map = Map_GetMutable(new_map_rb);
515
+
516
+ Arena_fuse(self->arena, arena);
517
+
518
+ while (upb_mapiter_next(self->map, &iter)) {
519
+ upb_msgval key = upb_mapiter_key(self->map, iter);
520
+ upb_msgval val = upb_mapiter_value(self->map, iter);
521
+ upb_map_set(new_map, key, val, arena);
522
+ }
523
+
524
+ return new_map_rb;
525
+ }
526
+
527
+ /*
528
+ * call-seq:
529
+ * Map.==(other) => boolean
530
+ *
531
+ * Compares this map to another. Maps are equal if they have identical key sets,
532
+ * and for each key, the values in both maps compare equal. Elements are
533
+ * compared as per normal Ruby semantics, by calling their :== methods (or
534
+ * performing a more efficient comparison for primitive types).
535
+ *
536
+ * Maps with dissimilar key types or value types/typeclasses are never equal,
537
+ * even if value comparison (for example, between integers and floats) would
538
+ * have otherwise indicated that every element has equal value.
539
+ */
540
+ VALUE Map_eq(VALUE _self, VALUE _other) {
541
+ Map* self = ruby_to_Map(_self);
542
+ Map* other;
543
+
544
+ // Allow comparisons to Ruby hashmaps by converting to a temporary Map
545
+ // instance. Slow, but workable.
546
+ if (TYPE(_other) == T_HASH) {
547
+ VALUE other_map = Map_new_this_type(self);
548
+ Map_merge_into_self(other_map, _other);
549
+ _other = other_map;
550
+ }
551
+
552
+ other = ruby_to_Map(_other);
553
+
554
+ if (self == other) {
555
+ return Qtrue;
556
+ }
557
+ if (self->key_type != other->key_type ||
558
+ self->value_type_info.type != other->value_type_info.type ||
559
+ self->value_type_class != other->value_type_class) {
560
+ return Qfalse;
561
+ }
562
+ if (upb_map_size(self->map) != upb_map_size(other->map)) {
563
+ return Qfalse;
564
+ }
565
+
566
+ // For each member of self, check that an equal member exists at the same key
567
+ // in other.
568
+ size_t iter = UPB_MAP_BEGIN;
569
+ while (upb_mapiter_next(self->map, &iter)) {
570
+ upb_msgval key = upb_mapiter_key(self->map, iter);
571
+ upb_msgval val = upb_mapiter_value(self->map, iter);
572
+ upb_msgval other_val;
573
+ if (!upb_map_get(other->map, key, &other_val)) {
574
+ // Not present in other map.
575
+ return Qfalse;
576
+ }
577
+ if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
578
+ // Present but different value.
579
+ return Qfalse;
580
+ }
581
+ }
582
+
583
+ return Qtrue;
584
+ }
585
+
586
+ /*
587
+ * call-seq:
588
+ * Message.freeze => self
589
+ *
590
+ * Freezes the message object. We have to intercept this so we can pin the
591
+ * Ruby object into memory so we don't forget it's frozen.
592
+ */
593
+ static VALUE Map_freeze(VALUE _self) {
594
+ Map* self = ruby_to_Map(_self);
595
+ if (!RB_OBJ_FROZEN(_self)) {
596
+ Arena_Pin(self->arena, _self);
597
+ RB_OBJ_FREEZE(_self);
598
+ }
599
+ return _self;
600
+ }
601
+
602
+ /*
603
+ * call-seq:
604
+ * Map.hash => hash_value
605
+ *
606
+ * Returns a hash value based on this map's contents.
607
+ */
608
+ VALUE Map_hash(VALUE _self) {
609
+ Map* self = ruby_to_Map(_self);
610
+ uint64_t hash = 0;
611
+
612
+ size_t iter = UPB_MAP_BEGIN;
613
+ TypeInfo key_info = {self->key_type};
614
+ while (upb_mapiter_next(self->map, &iter)) {
615
+ upb_msgval key = upb_mapiter_key(self->map, iter);
616
+ upb_msgval val = upb_mapiter_value(self->map, iter);
617
+ hash = Msgval_GetHash(key, key_info, hash);
618
+ hash = Msgval_GetHash(val, self->value_type_info, hash);
619
+ }
620
+
621
+ return LL2NUM(hash);
622
+ }
623
+
624
+ /*
625
+ * call-seq:
626
+ * Map.to_h => {}
627
+ *
628
+ * Returns a Ruby Hash object containing all the values within the map
629
+ */
630
+ VALUE Map_to_h(VALUE _self) {
631
+ Map* self = ruby_to_Map(_self);
632
+ return Map_CreateHash(self->map, self->key_type, self->value_type_info);
633
+ }
634
+
635
+ /*
636
+ * call-seq:
637
+ * Map.inspect => string
638
+ *
639
+ * Returns a string representing this map's elements. It will be formatted as
640
+ * "{key => value, key => value, ...}", with each key and value string
641
+ * representation computed by its own #inspect method.
642
+ */
643
+ VALUE Map_inspect(VALUE _self) {
644
+ Map* self = ruby_to_Map(_self);
645
+
646
+ StringBuilder* builder = StringBuilder_New();
647
+ Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
648
+ VALUE ret = StringBuilder_ToRubyString(builder);
649
+ StringBuilder_Free(builder);
650
+ return ret;
651
+ }
652
+
653
+ /*
654
+ * call-seq:
655
+ * Map.merge(other_map) => map
656
+ *
657
+ * Copies key/value pairs from other_map into a copy of this map. If a key is
658
+ * set in other_map and this map, the value from other_map overwrites the value
659
+ * in the new copy of this map. Returns the new copy of this map with merged
660
+ * contents.
661
+ */
662
+ static VALUE Map_merge(VALUE _self, VALUE hashmap) {
663
+ VALUE dupped = Map_dup(_self);
664
+ return Map_merge_into_self(dupped, hashmap);
665
+ }
666
+
667
+ void Map_register(VALUE module) {
668
+ VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
669
+ rb_define_alloc_func(klass, Map_alloc);
670
+ rb_gc_register_address(&cMap);
671
+ cMap = klass;
672
+
673
+ rb_define_method(klass, "initialize", Map_init, -1);
674
+ rb_define_method(klass, "each", Map_each, 0);
675
+ rb_define_method(klass, "keys", Map_keys, 0);
676
+ rb_define_method(klass, "values", Map_values, 0);
677
+ rb_define_method(klass, "[]", Map_index, 1);
678
+ rb_define_method(klass, "[]=", Map_index_set, 2);
679
+ rb_define_method(klass, "has_key?", Map_has_key, 1);
680
+ rb_define_method(klass, "delete", Map_delete, 1);
681
+ rb_define_method(klass, "clear", Map_clear, 0);
682
+ rb_define_method(klass, "length", Map_length, 0);
683
+ rb_define_method(klass, "size", Map_length, 0);
684
+ rb_define_method(klass, "dup", Map_dup, 0);
685
+ // Also define #clone so that we don't inherit Object#clone.
686
+ rb_define_method(klass, "clone", Map_dup, 0);
687
+ rb_define_method(klass, "==", Map_eq, 1);
688
+ rb_define_method(klass, "freeze", Map_freeze, 0);
689
+ rb_define_method(klass, "hash", Map_hash, 0);
690
+ rb_define_method(klass, "to_h", Map_to_h, 0);
691
+ rb_define_method(klass, "inspect", Map_inspect, 0);
692
+ rb_define_method(klass, "merge", Map_merge, 1);
693
+ rb_include_module(klass, rb_mEnumerable);
694
+ }