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.
- checksums.yaml +7 -0
- data/ext/google/protobuf_c/convert.c +361 -0
- data/ext/google/protobuf_c/convert.h +75 -0
- data/ext/google/protobuf_c/defs.c +1280 -0
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +28 -0
- data/ext/google/protobuf_c/map.c +702 -0
- data/ext/google/protobuf_c/map.h +66 -0
- data/ext/google/protobuf_c/message.c +1402 -0
- data/ext/google/protobuf_c/message.h +104 -0
- data/ext/google/protobuf_c/protobuf.c +480 -0
- data/ext/google/protobuf_c/protobuf.h +120 -0
- data/ext/google/protobuf_c/repeated_field.c +657 -0
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +11115 -0
- data/ext/google/protobuf_c/ruby-upb.h +5612 -0
- data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +21 -0
- data/ext/google/protobuf_c/third_party/utf8_range/naive.c +92 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +157 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +170 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +52 -0
- data/lib/google/3.1/protobuf_c.so +0 -0
- data/lib/google/protobuf/any_pb.rb +19 -0
- data/lib/google/protobuf/api_pb.rb +42 -0
- data/lib/google/protobuf/descriptor_dsl.rb +465 -0
- data/lib/google/protobuf/descriptor_pb.rb +269 -0
- data/lib/google/protobuf/duration_pb.rb +19 -0
- data/lib/google/protobuf/empty_pb.rb +17 -0
- data/lib/google/protobuf/field_mask_pb.rb +18 -0
- data/lib/google/protobuf/message_exts.rb +53 -0
- data/lib/google/protobuf/repeated_field.rb +201 -0
- data/lib/google/protobuf/source_context_pb.rb +18 -0
- data/lib/google/protobuf/struct_pb.rb +37 -0
- data/lib/google/protobuf/timestamp_pb.rb +19 -0
- data/lib/google/protobuf/type_pb.rb +92 -0
- data/lib/google/protobuf/well_known_types.rb +240 -0
- data/lib/google/protobuf/wrappers_pb.rb +50 -0
- data/lib/google/protobuf.rb +79 -0
- data/tests/basic.rb +739 -0
- data/tests/generated_code_test.rb +23 -0
- data/tests/stress.rb +38 -0
- 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
|
+
}
|