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.
- checksums.yaml +7 -0
- data/ext/google/protobuf_c/convert.c +348 -0
- data/ext/google/protobuf_c/convert.h +72 -0
- data/ext/google/protobuf_c/defs.c +1284 -0
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +20 -0
- data/ext/google/protobuf_c/map.c +694 -0
- data/ext/google/protobuf_c/map.h +67 -0
- data/ext/google/protobuf_c/message.c +1328 -0
- data/ext/google/protobuf_c/message.h +101 -0
- data/ext/google/protobuf_c/protobuf.c +470 -0
- data/ext/google/protobuf_c/protobuf.h +117 -0
- data/ext/google/protobuf_c/repeated_field.c +659 -0
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +9171 -0
- data/ext/google/protobuf_c/ruby-upb.h +4704 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +51 -0
- data/lib/google/2.3/protobuf_c.bundle +0 -0
- data/lib/google/2.4/protobuf_c.bundle +0 -0
- data/lib/google/2.5/protobuf_c.bundle +0 -0
- data/lib/google/2.6/protobuf_c.bundle +0 -0
- data/lib/google/2.7/protobuf_c.bundle +0 -0
- data/lib/google/3.0/protobuf_c.bundle +0 -0
- data/lib/google/protobuf/any_pb.rb +19 -0
- data/lib/google/protobuf/api_pb.rb +41 -0
- data/lib/google/protobuf/descriptor_dsl.rb +458 -0
- data/lib/google/protobuf/descriptor_pb.rb +266 -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 +188 -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 +91 -0
- data/lib/google/protobuf/well_known_types.rb +235 -0
- data/lib/google/protobuf/wrappers_pb.rb +50 -0
- data/lib/google/protobuf.rb +79 -0
- data/tests/basic.rb +640 -0
- data/tests/generated_code_test.rb +23 -0
- data/tests/stress.rb +38 -0
- metadata +144 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
// Protocol Buffers - Google's data interchange format
|
2
|
+
// Copyright 2008 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
|
+
#ifndef RUBY_PROTOBUF_MESSAGE_H_
|
32
|
+
#define RUBY_PROTOBUF_MESSAGE_H_
|
33
|
+
|
34
|
+
#include <ruby/ruby.h>
|
35
|
+
|
36
|
+
#include "protobuf.h"
|
37
|
+
#include "ruby-upb.h"
|
38
|
+
|
39
|
+
// Gets the underlying upb_msg* and upb_msgdef for the given Ruby message
|
40
|
+
// wrapper. Requires that |value| is indeed a message object.
|
41
|
+
const upb_msg *Message_Get(VALUE value, const upb_msgdef **m);
|
42
|
+
|
43
|
+
// Like Message_Get(), but checks that the object is not frozen and returns a
|
44
|
+
// mutable pointer.
|
45
|
+
upb_msg *Message_GetMutable(VALUE value, const upb_msgdef **m);
|
46
|
+
|
47
|
+
// Returns the Arena object for this message.
|
48
|
+
VALUE Message_GetArena(VALUE value);
|
49
|
+
|
50
|
+
// Converts |value| into a upb_msg value of the expected upb_msgdef type,
|
51
|
+
// raising an error if this is not possible. Used when assigning |value| to a
|
52
|
+
// field of another message, which means the message must be of a particular
|
53
|
+
// type.
|
54
|
+
//
|
55
|
+
// This will perform automatic conversions in some cases (for example, Time ->
|
56
|
+
// Google::Protobuf::Timestamp). If any new message is created, it will be
|
57
|
+
// created on |arena|, and any existing message will have its arena fused with
|
58
|
+
// |arena|.
|
59
|
+
const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
|
60
|
+
const char* name, upb_arena* arena);
|
61
|
+
|
62
|
+
// Gets or constructs a Ruby wrapper object for the given message. The wrapper
|
63
|
+
// object will reference |arena| and ensure that it outlives this object.
|
64
|
+
VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena);
|
65
|
+
|
66
|
+
// Gets the given field from this message.
|
67
|
+
VALUE Message_getfield(VALUE _self, const upb_fielddef* f);
|
68
|
+
|
69
|
+
// Implements #inspect for this message, printing the text to |b|.
|
70
|
+
void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
|
71
|
+
const upb_msgdef* m);
|
72
|
+
|
73
|
+
// Returns a hash value for the given message.
|
74
|
+
uint64_t Message_Hash(const upb_msg *msg, const upb_msgdef *m, uint64_t seed);
|
75
|
+
|
76
|
+
// Returns a deep copy of the given message.
|
77
|
+
upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
|
78
|
+
upb_arena *arena);
|
79
|
+
|
80
|
+
// Returns true if these two messages are equal.
|
81
|
+
bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
|
82
|
+
|
83
|
+
// Checks that this Ruby object is a message, and raises an exception if not.
|
84
|
+
void Message_CheckClass(VALUE klass);
|
85
|
+
|
86
|
+
// Returns a new Hash object containing the contents of this message.
|
87
|
+
VALUE Scalar_CreateHash(upb_msgval val, TypeInfo type_info);
|
88
|
+
|
89
|
+
// Creates a message class or enum module for this descriptor, respectively.
|
90
|
+
VALUE build_class_from_descriptor(VALUE descriptor);
|
91
|
+
VALUE build_module_from_enumdesc(VALUE _enumdesc);
|
92
|
+
|
93
|
+
// Returns the Descriptor/EnumDescriptor for the given message class or enum
|
94
|
+
// module, respectively. Returns nil if this is not a message class or enum
|
95
|
+
// module.
|
96
|
+
VALUE MessageOrEnum_GetDescriptor(VALUE klass);
|
97
|
+
|
98
|
+
// Call at startup to register all types in this module.
|
99
|
+
void Message_register(VALUE protobuf);
|
100
|
+
|
101
|
+
#endif // RUBY_PROTOBUF_MESSAGE_H_
|
@@ -0,0 +1,470 @@
|
|
1
|
+
// Protocol Buffers - Google's data interchange format
|
2
|
+
// Copyright 2014 Google Inc. All rights reserved.
|
3
|
+
// https://developers.google.com/protocol-buffers/
|
4
|
+
//
|
5
|
+
// Redistribution and use in source and binary forms, with or without
|
6
|
+
// modification, are permitted provided that the following conditions are
|
7
|
+
// met:
|
8
|
+
//
|
9
|
+
// * Redistributions of source code must retain the above copyright
|
10
|
+
// notice, this list of conditions and the following disclaimer.
|
11
|
+
// * Redistributions in binary form must reproduce the above
|
12
|
+
// copyright notice, this list of conditions and the following disclaimer
|
13
|
+
// in the documentation and/or other materials provided with the
|
14
|
+
// distribution.
|
15
|
+
// * Neither the name of Google Inc. nor the names of its
|
16
|
+
// contributors may be used to endorse or promote products derived from
|
17
|
+
// this software without specific prior written permission.
|
18
|
+
//
|
19
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
20
|
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
21
|
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
22
|
+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
25
|
+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
26
|
+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
27
|
+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
28
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
|
31
|
+
#include "protobuf.h"
|
32
|
+
|
33
|
+
#include <ruby/version.h>
|
34
|
+
|
35
|
+
#include "defs.h"
|
36
|
+
#include "map.h"
|
37
|
+
#include "message.h"
|
38
|
+
#include "repeated_field.h"
|
39
|
+
|
40
|
+
VALUE cParseError;
|
41
|
+
VALUE cTypeError;
|
42
|
+
|
43
|
+
const upb_fielddef* map_field_key(const upb_fielddef* field) {
|
44
|
+
const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
|
45
|
+
return upb_msgdef_itof(entry, 1);
|
46
|
+
}
|
47
|
+
|
48
|
+
const upb_fielddef* map_field_value(const upb_fielddef* field) {
|
49
|
+
const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
|
50
|
+
return upb_msgdef_itof(entry, 2);
|
51
|
+
}
|
52
|
+
|
53
|
+
// -----------------------------------------------------------------------------
|
54
|
+
// StringBuilder, for inspect
|
55
|
+
// -----------------------------------------------------------------------------
|
56
|
+
|
57
|
+
struct StringBuilder {
|
58
|
+
size_t size;
|
59
|
+
size_t cap;
|
60
|
+
char *data;
|
61
|
+
};
|
62
|
+
|
63
|
+
typedef struct StringBuilder StringBuilder;
|
64
|
+
|
65
|
+
static size_t StringBuilder_SizeOf(size_t cap) {
|
66
|
+
return sizeof(StringBuilder) + cap;
|
67
|
+
}
|
68
|
+
|
69
|
+
StringBuilder* StringBuilder_New() {
|
70
|
+
const size_t cap = 128;
|
71
|
+
StringBuilder* builder = malloc(sizeof(*builder));
|
72
|
+
builder->size = 0;
|
73
|
+
builder->cap = cap;
|
74
|
+
builder->data = malloc(builder->cap);
|
75
|
+
return builder;
|
76
|
+
}
|
77
|
+
|
78
|
+
void StringBuilder_Free(StringBuilder* b) {
|
79
|
+
free(b->data);
|
80
|
+
free(b);
|
81
|
+
}
|
82
|
+
|
83
|
+
void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...) {
|
84
|
+
size_t have = b->cap - b->size;
|
85
|
+
size_t n;
|
86
|
+
va_list args;
|
87
|
+
|
88
|
+
va_start(args, fmt);
|
89
|
+
n = vsnprintf(&b->data[b->size], have, fmt, args);
|
90
|
+
va_end(args);
|
91
|
+
|
92
|
+
if (have <= n) {
|
93
|
+
while (have <= n) {
|
94
|
+
b->cap *= 2;
|
95
|
+
have = b->cap - b->size;
|
96
|
+
}
|
97
|
+
b->data = realloc(b->data, StringBuilder_SizeOf(b->cap));
|
98
|
+
va_start(args, fmt);
|
99
|
+
n = vsnprintf(&b->data[b->size], have, fmt, args);
|
100
|
+
va_end(args);
|
101
|
+
PBRUBY_ASSERT(n < have);
|
102
|
+
}
|
103
|
+
|
104
|
+
b->size += n;
|
105
|
+
}
|
106
|
+
|
107
|
+
VALUE StringBuilder_ToRubyString(StringBuilder* b) {
|
108
|
+
VALUE ret = rb_str_new(b->data, b->size);
|
109
|
+
rb_enc_associate(ret, rb_utf8_encoding());
|
110
|
+
return ret;
|
111
|
+
}
|
112
|
+
|
113
|
+
static void StringBuilder_PrintEnum(StringBuilder* b, int32_t val,
|
114
|
+
const upb_enumdef* e) {
|
115
|
+
const char *name = upb_enumdef_iton(e, val);
|
116
|
+
if (name) {
|
117
|
+
StringBuilder_Printf(b, ":%s", name);
|
118
|
+
} else {
|
119
|
+
StringBuilder_Printf(b, "%" PRId32, val);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val,
|
124
|
+
TypeInfo info) {
|
125
|
+
switch (info.type) {
|
126
|
+
case UPB_TYPE_BOOL:
|
127
|
+
StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false");
|
128
|
+
break;
|
129
|
+
case UPB_TYPE_FLOAT: {
|
130
|
+
VALUE str = rb_inspect(DBL2NUM(val.float_val));
|
131
|
+
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
case UPB_TYPE_DOUBLE: {
|
135
|
+
VALUE str = rb_inspect(DBL2NUM(val.double_val));
|
136
|
+
StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
|
137
|
+
break;
|
138
|
+
}
|
139
|
+
case UPB_TYPE_INT32:
|
140
|
+
StringBuilder_Printf(b, "%" PRId32, val.int32_val);
|
141
|
+
break;
|
142
|
+
case UPB_TYPE_UINT32:
|
143
|
+
StringBuilder_Printf(b, "%" PRIu32, val.uint32_val);
|
144
|
+
break;
|
145
|
+
case UPB_TYPE_INT64:
|
146
|
+
StringBuilder_Printf(b, "%" PRId64, val.int64_val);
|
147
|
+
break;
|
148
|
+
case UPB_TYPE_UINT64:
|
149
|
+
StringBuilder_Printf(b, "%" PRIu64, val.uint64_val);
|
150
|
+
break;
|
151
|
+
case UPB_TYPE_STRING:
|
152
|
+
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
|
153
|
+
break;
|
154
|
+
case UPB_TYPE_BYTES:
|
155
|
+
StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
|
156
|
+
break;
|
157
|
+
case UPB_TYPE_ENUM:
|
158
|
+
StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef);
|
159
|
+
break;
|
160
|
+
case UPB_TYPE_MESSAGE:
|
161
|
+
Message_PrintMessage(b, val.msg_val, info.def.msgdef);
|
162
|
+
break;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
// -----------------------------------------------------------------------------
|
167
|
+
// Arena
|
168
|
+
// -----------------------------------------------------------------------------
|
169
|
+
|
170
|
+
typedef struct {
|
171
|
+
upb_arena *arena;
|
172
|
+
VALUE pinned_objs;
|
173
|
+
} Arena;
|
174
|
+
|
175
|
+
static void Arena_mark(void *data) {
|
176
|
+
Arena *arena = data;
|
177
|
+
rb_gc_mark(arena->pinned_objs);
|
178
|
+
}
|
179
|
+
|
180
|
+
static void Arena_free(void *data) {
|
181
|
+
Arena *arena = data;
|
182
|
+
upb_arena_free(arena->arena);
|
183
|
+
xfree(arena);
|
184
|
+
}
|
185
|
+
|
186
|
+
static VALUE cArena;
|
187
|
+
|
188
|
+
const rb_data_type_t Arena_type = {
|
189
|
+
"Google::Protobuf::Internal::Arena",
|
190
|
+
{ Arena_mark, Arena_free, NULL },
|
191
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
192
|
+
};
|
193
|
+
|
194
|
+
static VALUE Arena_alloc(VALUE klass) {
|
195
|
+
Arena *arena = ALLOC(Arena);
|
196
|
+
arena->arena = upb_arena_new();
|
197
|
+
arena->pinned_objs = Qnil;
|
198
|
+
return TypedData_Wrap_Struct(klass, &Arena_type, arena);
|
199
|
+
}
|
200
|
+
|
201
|
+
upb_arena *Arena_get(VALUE _arena) {
|
202
|
+
Arena *arena;
|
203
|
+
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
204
|
+
return arena->arena;
|
205
|
+
}
|
206
|
+
|
207
|
+
void Arena_fuse(VALUE _arena, upb_arena *other) {
|
208
|
+
Arena *arena;
|
209
|
+
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
210
|
+
if (!upb_arena_fuse(arena->arena, other)) {
|
211
|
+
rb_raise(rb_eRuntimeError,
|
212
|
+
"Unable to fuse arenas. This should never happen since Ruby does "
|
213
|
+
"not use initial blocks");
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
VALUE Arena_new() {
|
218
|
+
return Arena_alloc(cArena);
|
219
|
+
}
|
220
|
+
|
221
|
+
void Arena_Pin(VALUE _arena, VALUE obj) {
|
222
|
+
Arena *arena;
|
223
|
+
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
224
|
+
if (arena->pinned_objs == Qnil) {
|
225
|
+
arena->pinned_objs = rb_ary_new();
|
226
|
+
}
|
227
|
+
rb_ary_push(arena->pinned_objs, obj);
|
228
|
+
}
|
229
|
+
|
230
|
+
void Arena_register(VALUE module) {
|
231
|
+
VALUE internal = rb_define_module_under(module, "Internal");
|
232
|
+
VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject);
|
233
|
+
rb_define_alloc_func(klass, Arena_alloc);
|
234
|
+
rb_gc_register_address(&cArena);
|
235
|
+
cArena = klass;
|
236
|
+
}
|
237
|
+
|
238
|
+
// -----------------------------------------------------------------------------
|
239
|
+
// Object Cache
|
240
|
+
// -----------------------------------------------------------------------------
|
241
|
+
|
242
|
+
// A pointer -> Ruby Object cache that keeps references to Ruby wrapper
|
243
|
+
// objects. This allows us to look up any Ruby wrapper object by the address
|
244
|
+
// of the object it is wrapping. That way we can avoid ever creating two
|
245
|
+
// different wrapper objects for the same C object, which saves memory and
|
246
|
+
// preserves object identity.
|
247
|
+
//
|
248
|
+
// We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
|
249
|
+
// to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
|
250
|
+
// keys.
|
251
|
+
//
|
252
|
+
// We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
|
253
|
+
// means it may not be possible to fit a pointer into a Fixnum. Keys are
|
254
|
+
// pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
|
255
|
+
// they overflow and require allocating a Bignum, they could get collected
|
256
|
+
// prematurely, thus removing the cache entry. This happens on 64-bit Windows,
|
257
|
+
// on which pointers are 64 bits but longs are 32 bits. In this case, we enable
|
258
|
+
// the secondary Hash to hold the keys and prevent them from being collected.
|
259
|
+
|
260
|
+
#if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
|
261
|
+
#define USE_SECONDARY_MAP 0
|
262
|
+
#else
|
263
|
+
#define USE_SECONDARY_MAP 1
|
264
|
+
#endif
|
265
|
+
|
266
|
+
#if USE_SECONDARY_MAP
|
267
|
+
|
268
|
+
// Maps Numeric -> Object. The object is then used as a key into the WeakMap.
|
269
|
+
// This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
|
270
|
+
// The object is used only for its identity; it does not contain any data.
|
271
|
+
VALUE secondary_map = Qnil;
|
272
|
+
|
273
|
+
// Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
|
274
|
+
// iterates over the map which cannot happen in parallel with insertions, or
|
275
|
+
// Ruby will throw:
|
276
|
+
// can't add a new key into hash during iteration (RuntimeError)
|
277
|
+
VALUE secondary_map_mutex = Qnil;
|
278
|
+
|
279
|
+
// Lambda that will GC entries from the secondary map that are no longer present
|
280
|
+
// in the primary map.
|
281
|
+
VALUE gc_secondary_map_lambda = Qnil;
|
282
|
+
ID length;
|
283
|
+
|
284
|
+
extern VALUE weak_obj_cache;
|
285
|
+
|
286
|
+
static void SecondaryMap_Init() {
|
287
|
+
rb_gc_register_address(&secondary_map);
|
288
|
+
rb_gc_register_address(&gc_secondary_map_lambda);
|
289
|
+
rb_gc_register_address(&secondary_map_mutex);
|
290
|
+
secondary_map = rb_hash_new();
|
291
|
+
gc_secondary_map_lambda = rb_eval_string(
|
292
|
+
"->(secondary, weak) {\n"
|
293
|
+
" secondary.delete_if { |k, v| !weak.key?(v) }\n"
|
294
|
+
"}\n");
|
295
|
+
secondary_map_mutex = rb_mutex_new();
|
296
|
+
length = rb_intern("length");
|
297
|
+
}
|
298
|
+
|
299
|
+
// The secondary map is a regular Hash, and will never shrink on its own.
|
300
|
+
// The main object cache is a WeakMap that will automatically remove entries
|
301
|
+
// when the target object is no longer reachable, but unless we manually
|
302
|
+
// remove the corresponding entries from the secondary map, it will grow
|
303
|
+
// without bound.
|
304
|
+
//
|
305
|
+
// To avoid this unbounded growth we periodically remove entries from the
|
306
|
+
// secondary map that are no longer present in the WeakMap. The logic of
|
307
|
+
// how often to perform this GC is an artbirary tuning parameter that
|
308
|
+
// represents a straightforward CPU/memory tradeoff.
|
309
|
+
//
|
310
|
+
// Requires: secondary_map_mutex is held.
|
311
|
+
static void SecondaryMap_MaybeGC() {
|
312
|
+
PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
313
|
+
size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
|
314
|
+
size_t secondary_len = RHASH_SIZE(secondary_map);
|
315
|
+
if (secondary_len < weak_len) {
|
316
|
+
// Logically this case should not be possible: a valid entry cannot exist in
|
317
|
+
// the weak table unless there is a corresponding entry in the secondary
|
318
|
+
// table. It should *always* be the case that secondary_len >= weak_len.
|
319
|
+
//
|
320
|
+
// However ObjectSpace::WeakMap#length (and therefore weak_len) is
|
321
|
+
// unreliable: it overreports its true length by including non-live objects.
|
322
|
+
// However these non-live objects are not yielded in iteration, so we may
|
323
|
+
// have previously deleted them from the secondary map in a previous
|
324
|
+
// invocation of SecondaryMap_MaybeGC().
|
325
|
+
//
|
326
|
+
// In this case, we can't measure any waste, so we just return.
|
327
|
+
return;
|
328
|
+
}
|
329
|
+
size_t waste = secondary_len - weak_len;
|
330
|
+
// GC if we could remove at least 2000 entries or 20% of the table size
|
331
|
+
// (whichever is greater). Since the cost of the GC pass is O(N), we
|
332
|
+
// want to make sure that we condition this on overall table size, to
|
333
|
+
// avoid O(N^2) CPU costs.
|
334
|
+
size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
|
335
|
+
if (waste > threshold) {
|
336
|
+
rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2,
|
337
|
+
secondary_map, weak_obj_cache);
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
342
|
+
static VALUE SecondaryMap_Get(VALUE key, bool create) {
|
343
|
+
PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
|
344
|
+
VALUE ret = rb_hash_lookup(secondary_map, key);
|
345
|
+
if (ret == Qnil && create) {
|
346
|
+
SecondaryMap_MaybeGC();
|
347
|
+
ret = rb_class_new_instance(0, NULL, rb_cObject);
|
348
|
+
rb_hash_aset(secondary_map, key, ret);
|
349
|
+
}
|
350
|
+
return ret;
|
351
|
+
}
|
352
|
+
|
353
|
+
#endif
|
354
|
+
|
355
|
+
// Requires: secondary_map_mutex is held by this thread iff create == true.
|
356
|
+
static VALUE ObjectCache_GetKey(const void* key, bool create) {
|
357
|
+
VALUE key_val = (VALUE)key;
|
358
|
+
PBRUBY_ASSERT((key_val & 3) == 0);
|
359
|
+
VALUE ret = LL2NUM(key_val >> 2);
|
360
|
+
#if USE_SECONDARY_MAP
|
361
|
+
ret = SecondaryMap_Get(ret, create);
|
362
|
+
#endif
|
363
|
+
return ret;
|
364
|
+
}
|
365
|
+
|
366
|
+
// Public ObjectCache API.
|
367
|
+
|
368
|
+
VALUE weak_obj_cache = Qnil;
|
369
|
+
ID item_get;
|
370
|
+
ID item_set;
|
371
|
+
|
372
|
+
static void ObjectCache_Init() {
|
373
|
+
rb_gc_register_address(&weak_obj_cache);
|
374
|
+
VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
|
375
|
+
weak_obj_cache = rb_class_new_instance(0, NULL, klass);
|
376
|
+
item_get = rb_intern("[]");
|
377
|
+
item_set = rb_intern("[]=");
|
378
|
+
#if USE_SECONDARY_MAP
|
379
|
+
SecondaryMap_Init();
|
380
|
+
#endif
|
381
|
+
}
|
382
|
+
|
383
|
+
void ObjectCache_Add(const void* key, VALUE val) {
|
384
|
+
PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
|
385
|
+
#if USE_SECONDARY_MAP
|
386
|
+
rb_mutex_lock(secondary_map_mutex);
|
387
|
+
#endif
|
388
|
+
VALUE key_rb = ObjectCache_GetKey(key, true);
|
389
|
+
rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
|
390
|
+
#if USE_SECONDARY_MAP
|
391
|
+
rb_mutex_unlock(secondary_map_mutex);
|
392
|
+
#endif
|
393
|
+
PBRUBY_ASSERT(ObjectCache_Get(key) == val);
|
394
|
+
}
|
395
|
+
|
396
|
+
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
397
|
+
VALUE ObjectCache_Get(const void* key) {
|
398
|
+
VALUE key_rb = ObjectCache_GetKey(key, false);
|
399
|
+
return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
|
400
|
+
}
|
401
|
+
|
402
|
+
/*
|
403
|
+
* call-seq:
|
404
|
+
* Google::Protobuf.discard_unknown(msg)
|
405
|
+
*
|
406
|
+
* Discard unknown fields in the given message object and recursively discard
|
407
|
+
* unknown fields in submessages.
|
408
|
+
*/
|
409
|
+
static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
|
410
|
+
const upb_msgdef *m;
|
411
|
+
upb_msg *msg = Message_GetMutable(msg_rb, &m);
|
412
|
+
if (!upb_msg_discardunknown(msg, m, 128)) {
|
413
|
+
rb_raise(rb_eRuntimeError, "Messages nested too deeply.");
|
414
|
+
}
|
415
|
+
|
416
|
+
return Qnil;
|
417
|
+
}
|
418
|
+
|
419
|
+
/*
|
420
|
+
* call-seq:
|
421
|
+
* Google::Protobuf.deep_copy(obj) => copy_of_obj
|
422
|
+
*
|
423
|
+
* Performs a deep copy of a RepeatedField instance, a Map instance, or a
|
424
|
+
* message object, recursively copying its members.
|
425
|
+
*/
|
426
|
+
VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
|
427
|
+
VALUE klass = CLASS_OF(obj);
|
428
|
+
if (klass == cRepeatedField) {
|
429
|
+
return RepeatedField_deep_copy(obj);
|
430
|
+
} else if (klass == cMap) {
|
431
|
+
return Map_deep_copy(obj);
|
432
|
+
} else {
|
433
|
+
VALUE new_arena_rb = Arena_new();
|
434
|
+
upb_arena *new_arena = Arena_get(new_arena_rb);
|
435
|
+
const upb_msgdef *m;
|
436
|
+
const upb_msg *msg = Message_Get(obj, &m);
|
437
|
+
upb_msg* new_msg = Message_deep_copy(msg, m, new_arena);
|
438
|
+
return Message_GetRubyWrapper(new_msg, m, new_arena_rb);
|
439
|
+
}
|
440
|
+
}
|
441
|
+
|
442
|
+
// -----------------------------------------------------------------------------
|
443
|
+
// Initialization/entry point.
|
444
|
+
// -----------------------------------------------------------------------------
|
445
|
+
|
446
|
+
// This must be named "Init_protobuf_c" because the Ruby module is named
|
447
|
+
// "protobuf_c" -- the VM looks for this symbol in our .so.
|
448
|
+
__attribute__ ((visibility ("default")))
|
449
|
+
void Init_protobuf_c() {
|
450
|
+
ObjectCache_Init();
|
451
|
+
|
452
|
+
VALUE google = rb_define_module("Google");
|
453
|
+
VALUE protobuf = rb_define_module_under(google, "Protobuf");
|
454
|
+
|
455
|
+
Arena_register(protobuf);
|
456
|
+
Defs_register(protobuf);
|
457
|
+
RepeatedField_register(protobuf);
|
458
|
+
Map_register(protobuf);
|
459
|
+
Message_register(protobuf);
|
460
|
+
|
461
|
+
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
|
462
|
+
rb_gc_register_mark_object(cParseError);
|
463
|
+
cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
|
464
|
+
rb_gc_register_mark_object(cTypeError);
|
465
|
+
|
466
|
+
rb_define_singleton_method(protobuf, "discard_unknown",
|
467
|
+
Google_Protobuf_discard_unknown, 1);
|
468
|
+
rb_define_singleton_method(protobuf, "deep_copy",
|
469
|
+
Google_Protobuf_deep_copy, 1);
|
470
|
+
}
|
@@ -0,0 +1,117 @@
|
|
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
|
+
#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
32
|
+
#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|
33
|
+
|
34
|
+
#include <ruby/ruby.h>
|
35
|
+
#include <ruby/vm.h>
|
36
|
+
#include <ruby/encoding.h>
|
37
|
+
|
38
|
+
#include "ruby-upb.h"
|
39
|
+
#include "defs.h"
|
40
|
+
|
41
|
+
// These operate on a map field (i.e., a repeated field of submessages whose
|
42
|
+
// submessage type is a map-entry msgdef).
|
43
|
+
const upb_fielddef* map_field_key(const upb_fielddef* field);
|
44
|
+
const upb_fielddef* map_field_value(const upb_fielddef* field);
|
45
|
+
|
46
|
+
// -----------------------------------------------------------------------------
|
47
|
+
// Arena
|
48
|
+
// -----------------------------------------------------------------------------
|
49
|
+
|
50
|
+
// A Ruby object that wraps an underlying upb_arena. Any objects that are
|
51
|
+
// allocated from this arena should reference the Arena in rb_gc_mark(), to
|
52
|
+
// ensure that the object's underlying memory outlives any Ruby object that can
|
53
|
+
// reach it.
|
54
|
+
|
55
|
+
VALUE Arena_new();
|
56
|
+
upb_arena *Arena_get(VALUE arena);
|
57
|
+
|
58
|
+
// Fuses this arena to another, throwing a Ruby exception if this is not
|
59
|
+
// possible.
|
60
|
+
void Arena_fuse(VALUE arena, upb_arena *other);
|
61
|
+
|
62
|
+
// Pins this Ruby object to the lifetime of this arena, so that as long as the
|
63
|
+
// arena is alive this object will not be collected.
|
64
|
+
//
|
65
|
+
// We use this to guarantee that the "frozen" bit on the object will be
|
66
|
+
// remembered, even if the user drops their reference to this precise object.
|
67
|
+
void Arena_Pin(VALUE arena, VALUE obj);
|
68
|
+
|
69
|
+
// -----------------------------------------------------------------------------
|
70
|
+
// ObjectCache
|
71
|
+
// -----------------------------------------------------------------------------
|
72
|
+
|
73
|
+
// Global object cache from upb array/map/message/symtab to wrapper object.
|
74
|
+
//
|
75
|
+
// This is a conceptually "weak" cache, in that it does not prevent "val" from
|
76
|
+
// being collected (though in Ruby <2.7 is it effectively strong, due to
|
77
|
+
// implementation limitations).
|
78
|
+
|
79
|
+
// Adds an entry to the cache. The "arena" parameter must give the arena that
|
80
|
+
// "key" was allocated from. In Ruby <2.7.0, it will be used to remove the key
|
81
|
+
// from the cache when the arena is destroyed.
|
82
|
+
void ObjectCache_Add(const void* key, VALUE val);
|
83
|
+
|
84
|
+
// Returns the cached object for this key, if any. Otherwise returns Qnil.
|
85
|
+
VALUE ObjectCache_Get(const void* key);
|
86
|
+
|
87
|
+
// -----------------------------------------------------------------------------
|
88
|
+
// StringBuilder, for inspect
|
89
|
+
// -----------------------------------------------------------------------------
|
90
|
+
|
91
|
+
struct StringBuilder;
|
92
|
+
typedef struct StringBuilder StringBuilder;
|
93
|
+
|
94
|
+
StringBuilder* StringBuilder_New();
|
95
|
+
void StringBuilder_Free(StringBuilder* b);
|
96
|
+
void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...);
|
97
|
+
VALUE StringBuilder_ToRubyString(StringBuilder* b);
|
98
|
+
|
99
|
+
void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val, TypeInfo info);
|
100
|
+
|
101
|
+
// -----------------------------------------------------------------------------
|
102
|
+
// Utilities.
|
103
|
+
// -----------------------------------------------------------------------------
|
104
|
+
|
105
|
+
extern VALUE cTypeError;
|
106
|
+
|
107
|
+
#ifdef NDEBUG
|
108
|
+
#define PBRUBY_ASSERT(expr) do {} while (false && (expr))
|
109
|
+
#else
|
110
|
+
#define PBRUBY_ASSERT(expr) assert(expr)
|
111
|
+
#endif
|
112
|
+
|
113
|
+
#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
|
114
|
+
|
115
|
+
#define UPB_UNUSED(var) (void)var
|
116
|
+
|
117
|
+
#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
|