google-protobuf 4.31.0.rc.1-aarch64-linux-musl

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