google-protobuf 3.21.0.rc.2-x64-mingw-ucrt

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