google-protobuf 3.5.0 → 3.23.4
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 +5 -5
- 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 +770 -1254
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +15 -5
- data/ext/google/protobuf_c/map.c +312 -474
- data/ext/google/protobuf_c/map.h +66 -0
- data/ext/google/protobuf_c/message.c +1139 -372
- data/ext/google/protobuf_c/message.h +104 -0
- data/ext/google/protobuf_c/protobuf.c +418 -51
- data/ext/google/protobuf_c/protobuf.h +53 -485
- data/ext/google/protobuf_c/repeated_field.c +319 -316
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +13974 -0
- data/ext/google/protobuf_c/ruby-upb.h +11780 -0
- data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +22 -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 +21 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +4 -3
- data/lib/google/protobuf/any_pb.rb +26 -5
- data/lib/google/protobuf/api_pb.rb +31 -25
- data/lib/google/protobuf/descriptor_dsl.rb +465 -0
- data/lib/google/protobuf/descriptor_pb.rb +75 -0
- data/lib/google/protobuf/duration_pb.rb +26 -5
- data/lib/google/protobuf/empty_pb.rb +26 -3
- data/lib/google/protobuf/field_mask_pb.rb +26 -4
- data/lib/google/protobuf/message_exts.rb +9 -4
- data/lib/google/protobuf/plugin_pb.rb +47 -0
- data/lib/google/protobuf/repeated_field.rb +17 -4
- data/lib/google/protobuf/source_context_pb.rb +26 -4
- data/lib/google/protobuf/struct_pb.rb +28 -22
- data/lib/google/protobuf/timestamp_pb.rb +26 -5
- data/lib/google/protobuf/type_pb.rb +37 -76
- data/lib/google/protobuf/well_known_types.rb +32 -4
- data/lib/google/protobuf/wrappers_pb.rb +35 -37
- data/lib/google/protobuf.rb +11 -8
- metadata +29 -37
- data/ext/google/protobuf_c/encode_decode.c +0 -1307
- data/ext/google/protobuf_c/storage.c +0 -904
- data/ext/google/protobuf_c/upb.c +0 -14913
- data/ext/google/protobuf_c/upb.h +0 -8969
- data/tests/basic.rb +0 -1403
- data/tests/generated_code_test.rb +0 -19
- data/tests/stress.rb +0 -38
@@ -28,97 +28,392 @@
|
|
28
28
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
29
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
30
|
|
31
|
+
#include "message.h"
|
32
|
+
|
33
|
+
#include "convert.h"
|
34
|
+
#include "defs.h"
|
35
|
+
#include "map.h"
|
31
36
|
#include "protobuf.h"
|
37
|
+
#include "repeated_field.h"
|
32
38
|
|
33
|
-
|
34
|
-
|
35
|
-
|
39
|
+
static VALUE cParseError = Qnil;
|
40
|
+
static VALUE cAbstractMessage = Qnil;
|
41
|
+
static ID descriptor_instancevar_interned;
|
36
42
|
|
37
|
-
|
38
|
-
return ((
|
43
|
+
static VALUE initialize_rb_class_with_no_args(VALUE klass) {
|
44
|
+
return rb_funcall(klass, rb_intern("new"), 0);
|
39
45
|
}
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
layout_mark(self->descriptor->layout, Message_data(self));
|
47
|
+
VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
|
48
|
+
return rb_ivar_get(klass, descriptor_instancevar_interned);
|
44
49
|
}
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
// -----------------------------------------------------------------------------
|
52
|
+
// Class/module creation from msgdefs and enumdefs, respectively.
|
53
|
+
// -----------------------------------------------------------------------------
|
54
|
+
|
55
|
+
typedef struct {
|
56
|
+
// IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
|
57
|
+
// macro to update VALUE references, as to trigger write barriers.
|
58
|
+
VALUE arena;
|
59
|
+
const upb_Message* msg; // Can get as mutable when non-frozen.
|
60
|
+
const upb_MessageDef*
|
61
|
+
msgdef; // kept alive by self.class.descriptor reference.
|
62
|
+
} Message;
|
63
|
+
|
64
|
+
static void Message_mark(void* _self) {
|
65
|
+
Message* self = (Message*)_self;
|
66
|
+
rb_gc_mark(self->arena);
|
53
67
|
}
|
54
68
|
|
55
|
-
rb_data_type_t Message_type = {
|
56
|
-
|
57
|
-
|
69
|
+
static rb_data_type_t Message_type = {
|
70
|
+
"Google::Protobuf::Message",
|
71
|
+
{Message_mark, RUBY_DEFAULT_FREE, NULL},
|
72
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
58
73
|
};
|
59
74
|
|
60
|
-
|
75
|
+
static Message* ruby_to_Message(VALUE msg_rb) {
|
76
|
+
Message* msg;
|
77
|
+
TypedData_Get_Struct(msg_rb, Message, &Message_type, msg);
|
78
|
+
return msg;
|
79
|
+
}
|
80
|
+
|
81
|
+
static VALUE Message_alloc(VALUE klass) {
|
61
82
|
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
|
62
|
-
|
63
|
-
MessageHeader* msg = (MessageHeader*)ALLOC_N(
|
64
|
-
uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
83
|
+
Message* msg = ALLOC(Message);
|
65
84
|
VALUE ret;
|
66
85
|
|
67
|
-
|
86
|
+
msg->msgdef = Descriptor_GetMsgDef(descriptor);
|
87
|
+
msg->arena = Qnil;
|
88
|
+
msg->msg = NULL;
|
68
89
|
|
69
|
-
// We wrap first so that everything in the message object is GC-rooted in case
|
70
|
-
// a collection happens during object creation in layout_init().
|
71
90
|
ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
|
72
|
-
msg->descriptor = desc;
|
73
91
|
rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
|
74
92
|
|
75
|
-
|
93
|
+
return ret;
|
94
|
+
}
|
76
95
|
|
77
|
-
|
96
|
+
const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
|
97
|
+
Message* msg = ruby_to_Message(msg_rb);
|
98
|
+
if (m) *m = msg->msgdef;
|
99
|
+
return msg->msg;
|
100
|
+
}
|
78
101
|
|
79
|
-
|
102
|
+
upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
|
103
|
+
rb_check_frozen(msg_rb);
|
104
|
+
return (upb_Message*)Message_Get(msg_rb, m);
|
80
105
|
}
|
81
106
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
107
|
+
void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
|
108
|
+
Message* self = ruby_to_Message(self_);
|
109
|
+
self->msg = msg;
|
110
|
+
RB_OBJ_WRITE(self_, &self->arena, arena);
|
111
|
+
ObjectCache_Add(msg, self_);
|
112
|
+
}
|
88
113
|
|
89
|
-
|
90
|
-
|
91
|
-
|
114
|
+
VALUE Message_GetArena(VALUE msg_rb) {
|
115
|
+
Message* msg = ruby_to_Message(msg_rb);
|
116
|
+
return msg->arena;
|
117
|
+
}
|
118
|
+
|
119
|
+
void Message_CheckClass(VALUE klass) {
|
120
|
+
if (rb_get_alloc_func(klass) != &Message_alloc) {
|
121
|
+
rb_raise(rb_eArgError,
|
122
|
+
"Message class was not returned by the DescriptorPool.");
|
92
123
|
}
|
93
|
-
|
94
|
-
// oneof_case field.
|
95
|
-
upb_oneof_begin(&it, o);
|
96
|
-
assert(!upb_oneof_done(&it));
|
97
|
-
first_field = upb_oneof_iter_field(&it);
|
98
|
-
assert(upb_fielddef_containingoneof(first_field) != NULL);
|
124
|
+
}
|
99
125
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
|
126
|
+
VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
127
|
+
VALUE arena) {
|
128
|
+
if (msg == NULL) return Qnil;
|
104
129
|
|
105
|
-
|
106
|
-
|
130
|
+
VALUE val = ObjectCache_Get(msg);
|
131
|
+
|
132
|
+
if (val == Qnil) {
|
133
|
+
VALUE klass = Descriptor_DefToClass(m);
|
134
|
+
val = Message_alloc(klass);
|
135
|
+
Message_InitPtr(val, msg, arena);
|
136
|
+
}
|
137
|
+
|
138
|
+
return val;
|
139
|
+
}
|
140
|
+
|
141
|
+
void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
|
142
|
+
const upb_MessageDef* m) {
|
143
|
+
bool first = true;
|
144
|
+
int n = upb_MessageDef_FieldCount(m);
|
145
|
+
VALUE klass = Descriptor_DefToClass(m);
|
146
|
+
StringBuilder_Printf(b, "<%s: ", rb_class2name(klass));
|
147
|
+
|
148
|
+
for (int i = 0; i < n; i++) {
|
149
|
+
const upb_FieldDef* field = upb_MessageDef_Field(m, i);
|
150
|
+
|
151
|
+
if (upb_FieldDef_HasPresence(field) &&
|
152
|
+
!upb_Message_HasFieldByDef(msg, field)) {
|
153
|
+
continue;
|
154
|
+
}
|
155
|
+
|
156
|
+
if (!first) {
|
157
|
+
StringBuilder_Printf(b, ", ");
|
158
|
+
} else {
|
159
|
+
first = false;
|
160
|
+
}
|
161
|
+
|
162
|
+
upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field);
|
163
|
+
|
164
|
+
StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field));
|
165
|
+
|
166
|
+
if (upb_FieldDef_IsMap(field)) {
|
167
|
+
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
|
168
|
+
const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
|
169
|
+
const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
|
170
|
+
TypeInfo val_info = TypeInfo_get(val_f);
|
171
|
+
Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info);
|
172
|
+
} else if (upb_FieldDef_IsRepeated(field)) {
|
173
|
+
RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field));
|
174
|
+
} else {
|
175
|
+
StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field));
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
StringBuilder_Printf(b, ">");
|
180
|
+
}
|
181
|
+
|
182
|
+
// Helper functions for #method_missing ////////////////////////////////////////
|
183
|
+
|
184
|
+
enum {
|
185
|
+
METHOD_UNKNOWN = 0,
|
186
|
+
METHOD_GETTER = 1,
|
187
|
+
METHOD_SETTER = 2,
|
188
|
+
METHOD_CLEAR = 3,
|
189
|
+
METHOD_PRESENCE = 4,
|
190
|
+
METHOD_ENUM_GETTER = 5,
|
191
|
+
METHOD_WRAPPER_GETTER = 6,
|
192
|
+
METHOD_WRAPPER_SETTER = 7
|
193
|
+
};
|
194
|
+
|
195
|
+
// Check if the field is a well known wrapper type
|
196
|
+
static bool IsWrapper(const upb_MessageDef* m) {
|
197
|
+
if (!m) return false;
|
198
|
+
switch (upb_MessageDef_WellKnownType(m)) {
|
199
|
+
case kUpb_WellKnown_DoubleValue:
|
200
|
+
case kUpb_WellKnown_FloatValue:
|
201
|
+
case kUpb_WellKnown_Int64Value:
|
202
|
+
case kUpb_WellKnown_UInt64Value:
|
203
|
+
case kUpb_WellKnown_Int32Value:
|
204
|
+
case kUpb_WellKnown_UInt32Value:
|
205
|
+
case kUpb_WellKnown_StringValue:
|
206
|
+
case kUpb_WellKnown_BytesValue:
|
207
|
+
case kUpb_WellKnown_BoolValue:
|
208
|
+
return true;
|
209
|
+
default:
|
210
|
+
return false;
|
107
211
|
}
|
212
|
+
}
|
213
|
+
|
214
|
+
static bool IsFieldWrapper(const upb_FieldDef* f) {
|
215
|
+
return IsWrapper(upb_FieldDef_MessageSubDef(f));
|
216
|
+
}
|
217
|
+
|
218
|
+
static bool Match(const upb_MessageDef* m, const char* name,
|
219
|
+
const upb_FieldDef** f, const upb_OneofDef** o,
|
220
|
+
const char* prefix, const char* suffix) {
|
221
|
+
size_t sp = strlen(prefix);
|
222
|
+
size_t ss = strlen(suffix);
|
223
|
+
size_t sn = strlen(name);
|
224
|
+
|
225
|
+
if (sn <= sp + ss) return false;
|
226
|
+
|
227
|
+
if (memcmp(name, prefix, sp) != 0 ||
|
228
|
+
memcmp(name + sn - ss, suffix, ss) != 0) {
|
229
|
+
return false;
|
230
|
+
}
|
231
|
+
|
232
|
+
return upb_MessageDef_FindByNameWithSize(m, name + sp, sn - sp - ss, f, o);
|
233
|
+
}
|
108
234
|
|
109
|
-
|
110
|
-
|
111
|
-
|
235
|
+
static int extract_method_call(VALUE method_name, Message* self,
|
236
|
+
const upb_FieldDef** f, const upb_OneofDef** o) {
|
237
|
+
const upb_MessageDef* m = self->msgdef;
|
238
|
+
const char* name;
|
239
|
+
|
240
|
+
Check_Type(method_name, T_SYMBOL);
|
241
|
+
name = rb_id2name(SYM2ID(method_name));
|
242
|
+
|
243
|
+
if (Match(m, name, f, o, "", "")) return METHOD_GETTER;
|
244
|
+
if (Match(m, name, f, o, "", "=")) return METHOD_SETTER;
|
245
|
+
if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
|
246
|
+
if (Match(m, name, f, o, "has_", "?") &&
|
247
|
+
(*o || (*f && upb_FieldDef_HasPresence(*f)))) {
|
248
|
+
return METHOD_PRESENCE;
|
249
|
+
}
|
250
|
+
if (Match(m, name, f, o, "", "_as_value") && *f &&
|
251
|
+
!upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
|
252
|
+
return METHOD_WRAPPER_GETTER;
|
253
|
+
}
|
254
|
+
if (Match(m, name, f, o, "", "_as_value=") && *f &&
|
255
|
+
!upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
|
256
|
+
return METHOD_WRAPPER_SETTER;
|
257
|
+
}
|
258
|
+
if (Match(m, name, f, o, "", "_const") && *f &&
|
259
|
+
upb_FieldDef_CType(*f) == kUpb_CType_Enum) {
|
260
|
+
return METHOD_ENUM_GETTER;
|
261
|
+
}
|
262
|
+
|
263
|
+
return METHOD_UNKNOWN;
|
264
|
+
}
|
265
|
+
|
266
|
+
static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
|
267
|
+
int accessor_type) {
|
268
|
+
Message* self = ruby_to_Message(_self);
|
269
|
+
const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
|
270
|
+
|
271
|
+
switch (accessor_type) {
|
272
|
+
case METHOD_PRESENCE:
|
273
|
+
return oneof_field == NULL ? Qfalse : Qtrue;
|
274
|
+
case METHOD_CLEAR:
|
275
|
+
if (oneof_field != NULL) {
|
276
|
+
upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL),
|
277
|
+
oneof_field);
|
278
|
+
}
|
279
|
+
return Qnil;
|
280
|
+
case METHOD_GETTER:
|
281
|
+
return oneof_field == NULL
|
282
|
+
? Qnil
|
283
|
+
: ID2SYM(rb_intern(upb_FieldDef_Name(oneof_field)));
|
284
|
+
case METHOD_SETTER:
|
285
|
+
rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
|
286
|
+
}
|
287
|
+
rb_raise(rb_eRuntimeError, "Invalid access of oneof field.");
|
288
|
+
}
|
112
289
|
|
113
|
-
|
290
|
+
static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
|
291
|
+
upb_Arena* arena) {
|
292
|
+
upb_MessageValue msgval;
|
293
|
+
if (upb_FieldDef_IsMap(f)) {
|
294
|
+
msgval.map_val = Map_GetUpbMap(val, f, arena);
|
295
|
+
} else if (upb_FieldDef_IsRepeated(f)) {
|
296
|
+
msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
|
297
|
+
} else {
|
298
|
+
if (val == Qnil &&
|
299
|
+
(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) {
|
300
|
+
upb_Message_ClearFieldByDef(msg, f);
|
301
|
+
return;
|
302
|
+
}
|
303
|
+
msgval =
|
304
|
+
Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
|
305
|
+
}
|
306
|
+
upb_Message_SetFieldByDef(msg, f, msgval, arena);
|
307
|
+
}
|
308
|
+
|
309
|
+
VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
|
310
|
+
Message* self = ruby_to_Message(_self);
|
311
|
+
// This is a special-case: upb_Message_Mutable() for map & array are logically
|
312
|
+
// const (they will not change what is serialized) but physically
|
313
|
+
// non-const, as they do allocate a repeated field or map. The logical
|
314
|
+
// constness means it's ok to do even if the message is frozen.
|
315
|
+
upb_Message* msg = (upb_Message*)self->msg;
|
316
|
+
upb_Arena* arena = Arena_get(self->arena);
|
317
|
+
if (upb_FieldDef_IsMap(f)) {
|
318
|
+
upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
|
319
|
+
const upb_FieldDef* key_f = map_field_key(f);
|
320
|
+
const upb_FieldDef* val_f = map_field_value(f);
|
321
|
+
upb_CType key_type = upb_FieldDef_CType(key_f);
|
322
|
+
TypeInfo value_type_info = TypeInfo_get(val_f);
|
323
|
+
return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
|
324
|
+
} else if (upb_FieldDef_IsRepeated(f)) {
|
325
|
+
upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
|
326
|
+
return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
|
327
|
+
} else if (upb_FieldDef_IsSubMessage(f)) {
|
328
|
+
if (!upb_Message_HasFieldByDef(self->msg, f)) return Qnil;
|
329
|
+
upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
|
330
|
+
const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
|
331
|
+
return Message_GetRubyWrapper(submsg, m, self->arena);
|
332
|
+
} else {
|
333
|
+
upb_MessageValue msgval = upb_Message_GetFieldByDef(self->msg, f);
|
334
|
+
return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
|
335
|
+
}
|
336
|
+
}
|
337
|
+
|
338
|
+
static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
|
339
|
+
int accessor_type, int argc, VALUE* argv) {
|
340
|
+
upb_Arena* arena = Arena_get(Message_GetArena(_self));
|
341
|
+
|
342
|
+
switch (accessor_type) {
|
343
|
+
case METHOD_SETTER:
|
344
|
+
Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
|
345
|
+
return Qnil;
|
346
|
+
case METHOD_CLEAR:
|
347
|
+
upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f);
|
348
|
+
return Qnil;
|
349
|
+
case METHOD_PRESENCE:
|
350
|
+
if (!upb_FieldDef_HasPresence(f)) {
|
351
|
+
rb_raise(rb_eRuntimeError, "Field does not have presence.");
|
352
|
+
}
|
353
|
+
return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f);
|
354
|
+
case METHOD_WRAPPER_GETTER: {
|
355
|
+
Message* self = ruby_to_Message(_self);
|
356
|
+
if (upb_Message_HasFieldByDef(self->msg, f)) {
|
357
|
+
PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
|
358
|
+
!upb_FieldDef_IsRepeated(f));
|
359
|
+
upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f);
|
360
|
+
const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
|
361
|
+
const upb_FieldDef* value_f =
|
362
|
+
upb_MessageDef_FindFieldByNumber(wrapper_m, 1);
|
363
|
+
upb_MessageValue value =
|
364
|
+
upb_Message_GetFieldByDef(wrapper.msg_val, value_f);
|
365
|
+
return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
|
366
|
+
} else {
|
367
|
+
return Qnil;
|
368
|
+
}
|
369
|
+
}
|
370
|
+
case METHOD_WRAPPER_SETTER: {
|
371
|
+
upb_Message* msg = Message_GetMutable(_self, NULL);
|
372
|
+
if (argv[1] == Qnil) {
|
373
|
+
upb_Message_ClearFieldByDef(msg, f);
|
374
|
+
} else {
|
375
|
+
const upb_FieldDef* val_f =
|
376
|
+
upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1);
|
377
|
+
upb_MessageValue msgval = Convert_RubyToUpb(
|
378
|
+
argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
|
379
|
+
upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
|
380
|
+
upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
|
381
|
+
}
|
382
|
+
return Qnil;
|
383
|
+
}
|
384
|
+
case METHOD_ENUM_GETTER: {
|
385
|
+
upb_MessageValue msgval =
|
386
|
+
upb_Message_GetFieldByDef(Message_Get(_self, NULL), f);
|
387
|
+
|
388
|
+
if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
|
389
|
+
// Map repeated fields to a new type with ints
|
390
|
+
VALUE arr = rb_ary_new();
|
391
|
+
size_t i, n = upb_Array_Size(msgval.array_val);
|
392
|
+
for (i = 0; i < n; i++) {
|
393
|
+
upb_MessageValue elem = upb_Array_Get(msgval.array_val, i);
|
394
|
+
rb_ary_push(arr, INT2NUM(elem.int32_val));
|
395
|
+
}
|
396
|
+
return arr;
|
397
|
+
} else {
|
398
|
+
return INT2NUM(msgval.int32_val);
|
399
|
+
}
|
400
|
+
}
|
401
|
+
case METHOD_GETTER:
|
402
|
+
return Message_getfield(_self, f);
|
403
|
+
default:
|
404
|
+
rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d",
|
405
|
+
accessor_type);
|
406
|
+
}
|
114
407
|
}
|
115
408
|
|
116
409
|
/*
|
117
410
|
* call-seq:
|
118
411
|
* Message.method_missing(*args)
|
119
412
|
*
|
120
|
-
* Provides accessors and setters
|
121
|
-
*
|
413
|
+
* Provides accessors and setters and methods to clear and check for presence of
|
414
|
+
* message fields according to their field names.
|
415
|
+
*
|
416
|
+
* For any field whose name does not conflict with a built-in method, an
|
122
417
|
* accessor is provided with the same name as the field, and a setter is
|
123
418
|
* provided with the name of the field plus the '=' suffix. Thus, given a
|
124
419
|
* message instance 'msg' with field 'foo', the following code is valid:
|
@@ -129,117 +424,187 @@ static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
|
|
129
424
|
* This method also provides read-only accessors for oneofs. If a oneof exists
|
130
425
|
* with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
|
131
426
|
* the name of the field in that oneof that is currently set, or nil if none.
|
427
|
+
*
|
428
|
+
* It also provides methods of the form 'clear_fieldname' to clear the value
|
429
|
+
* of the field 'fieldname'. For basic data types, this will set the default
|
430
|
+
* value of the field.
|
431
|
+
*
|
432
|
+
* Additionally, it provides methods of the form 'has_fieldname?', which returns
|
433
|
+
* true if the field 'fieldname' is set in the message object, else false. For
|
434
|
+
* 'proto3' syntax, calling this for a basic type field will result in an error.
|
132
435
|
*/
|
133
|
-
VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
const upb_oneofdef* o;
|
140
|
-
const upb_fielddef* f;
|
141
|
-
|
142
|
-
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
|
436
|
+
static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
437
|
+
Message* self = ruby_to_Message(_self);
|
438
|
+
const upb_OneofDef* o;
|
439
|
+
const upb_FieldDef* f;
|
440
|
+
int accessor_type;
|
441
|
+
|
143
442
|
if (argc < 1) {
|
144
443
|
rb_raise(rb_eArgError, "Expected method name as first argument.");
|
145
444
|
}
|
146
|
-
method_name = argv[0];
|
147
|
-
if (!SYMBOL_P(method_name)) {
|
148
|
-
rb_raise(rb_eArgError, "Expected symbol as method name.");
|
149
|
-
}
|
150
|
-
method_str = rb_id2str(SYM2ID(method_name));
|
151
|
-
name = RSTRING_PTR(method_str);
|
152
|
-
name_len = RSTRING_LEN(method_str);
|
153
|
-
setter = false;
|
154
445
|
|
155
|
-
|
156
|
-
if (name[name_len - 1] == '=') {
|
157
|
-
setter = true;
|
158
|
-
name_len--;
|
159
|
-
}
|
446
|
+
accessor_type = extract_method_call(argv[0], self, &f, &o);
|
160
447
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
448
|
+
if (accessor_type == METHOD_UNKNOWN) return rb_call_super(argc, argv);
|
449
|
+
|
450
|
+
// Validate argument count.
|
451
|
+
switch (accessor_type) {
|
452
|
+
case METHOD_SETTER:
|
453
|
+
case METHOD_WRAPPER_SETTER:
|
454
|
+
if (argc != 2) {
|
455
|
+
rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
|
456
|
+
}
|
457
|
+
rb_check_frozen(_self);
|
458
|
+
break;
|
459
|
+
default:
|
460
|
+
if (argc != 1) {
|
461
|
+
rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc);
|
462
|
+
}
|
463
|
+
break;
|
165
464
|
}
|
166
465
|
|
466
|
+
// Dispatch accessor.
|
167
467
|
if (o != NULL) {
|
168
|
-
|
169
|
-
if (setter) {
|
170
|
-
rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
|
171
|
-
}
|
172
|
-
return which_oneof_field(self, o);
|
468
|
+
return Message_oneof_accessor(_self, o, accessor_type);
|
173
469
|
} else {
|
174
|
-
|
175
|
-
assert(f);
|
176
|
-
if (setter) {
|
177
|
-
if (argc < 2) {
|
178
|
-
rb_raise(rb_eArgError, "No value provided to setter.");
|
179
|
-
}
|
180
|
-
layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
|
181
|
-
return Qnil;
|
182
|
-
} else {
|
183
|
-
return layout_get(self->descriptor->layout, Message_data(self), f);
|
184
|
-
}
|
470
|
+
return Message_field_accessor(_self, f, accessor_type, argc, argv);
|
185
471
|
}
|
186
472
|
}
|
187
473
|
|
188
|
-
VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
bool setter;
|
194
|
-
const upb_oneofdef* o;
|
195
|
-
const upb_fielddef* f;
|
474
|
+
static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
|
475
|
+
Message* self = ruby_to_Message(_self);
|
476
|
+
const upb_OneofDef* o;
|
477
|
+
const upb_FieldDef* f;
|
478
|
+
int accessor_type;
|
196
479
|
|
197
|
-
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
|
198
480
|
if (argc < 1) {
|
199
481
|
rb_raise(rb_eArgError, "Expected method name as first argument.");
|
200
482
|
}
|
201
|
-
|
202
|
-
|
203
|
-
|
483
|
+
|
484
|
+
accessor_type = extract_method_call(argv[0], self, &f, &o);
|
485
|
+
|
486
|
+
if (accessor_type == METHOD_UNKNOWN) {
|
487
|
+
return rb_call_super(argc, argv);
|
488
|
+
} else if (o != NULL) {
|
489
|
+
return accessor_type == METHOD_SETTER ? Qfalse : Qtrue;
|
490
|
+
} else {
|
491
|
+
return Qtrue;
|
204
492
|
}
|
205
|
-
|
206
|
-
name = RSTRING_PTR(method_str);
|
207
|
-
name_len = RSTRING_LEN(method_str);
|
208
|
-
setter = false;
|
493
|
+
}
|
209
494
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
495
|
+
void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
|
496
|
+
upb_Arena* arena);
|
497
|
+
|
498
|
+
typedef struct {
|
499
|
+
upb_Map* map;
|
500
|
+
TypeInfo key_type;
|
501
|
+
TypeInfo val_type;
|
502
|
+
upb_Arena* arena;
|
503
|
+
} MapInit;
|
504
|
+
|
505
|
+
static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
506
|
+
MapInit* map_init = (MapInit*)_self;
|
507
|
+
upb_MessageValue k, v;
|
508
|
+
k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
|
509
|
+
|
510
|
+
if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
|
511
|
+
upb_MiniTable* t = upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
|
512
|
+
upb_Message* msg = upb_Message_New(t, map_init->arena);
|
513
|
+
Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
|
514
|
+
map_init->arena);
|
515
|
+
v.msg_val = msg;
|
516
|
+
} else {
|
517
|
+
v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena);
|
214
518
|
}
|
519
|
+
upb_Map_Set(map_init->map, k, v, map_init->arena);
|
520
|
+
return ST_CONTINUE;
|
521
|
+
}
|
215
522
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
523
|
+
static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val,
|
524
|
+
upb_Arena* arena) {
|
525
|
+
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
|
526
|
+
const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
|
527
|
+
const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
|
528
|
+
if (TYPE(val) != T_HASH) {
|
529
|
+
rb_raise(rb_eArgError,
|
530
|
+
"Expected Hash object as initializer value for map field '%s' "
|
531
|
+
"(given %s).",
|
532
|
+
upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
|
220
533
|
}
|
221
|
-
|
222
|
-
|
534
|
+
MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena};
|
535
|
+
rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init);
|
536
|
+
}
|
537
|
+
|
538
|
+
static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
|
539
|
+
upb_Arena* arena) {
|
540
|
+
if (info.type == kUpb_CType_Message) {
|
541
|
+
upb_MessageValue msgval;
|
542
|
+
upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
|
543
|
+
upb_Message* msg = upb_Message_New(t, arena);
|
544
|
+
Message_InitFromValue(msg, info.def.msgdef, val, arena);
|
545
|
+
msgval.msg_val = msg;
|
546
|
+
return msgval;
|
547
|
+
} else {
|
548
|
+
return Convert_RubyToUpb(val, "", info, arena);
|
223
549
|
}
|
224
|
-
return Qtrue;
|
225
550
|
}
|
226
551
|
|
227
|
-
|
228
|
-
|
229
|
-
|
552
|
+
static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f,
|
553
|
+
VALUE val, upb_Arena* arena) {
|
554
|
+
TypeInfo type_info = TypeInfo_get(f);
|
230
555
|
|
231
|
-
|
232
|
-
|
556
|
+
if (TYPE(val) != T_ARRAY) {
|
557
|
+
rb_raise(rb_eArgError,
|
558
|
+
"Expected array as initializer value for repeated field '%s' "
|
559
|
+
"(given %s).",
|
560
|
+
upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
|
561
|
+
}
|
562
|
+
|
563
|
+
for (int i = 0; i < RARRAY_LEN(val); i++) {
|
564
|
+
VALUE entry = rb_ary_entry(val, i);
|
565
|
+
upb_MessageValue msgval;
|
566
|
+
if (upb_FieldDef_IsSubMessage(f) && TYPE(entry) == T_HASH) {
|
567
|
+
msgval = MessageValue_FromValue(entry, type_info, arena);
|
568
|
+
} else {
|
569
|
+
msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena);
|
570
|
+
}
|
571
|
+
upb_Array_Append(arr, msgval, arena);
|
572
|
+
}
|
573
|
+
}
|
233
574
|
|
234
|
-
|
235
|
-
|
575
|
+
static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
|
576
|
+
VALUE val, upb_Arena* arena) {
|
577
|
+
if (TYPE(val) == T_NIL) return;
|
578
|
+
|
579
|
+
if (upb_FieldDef_IsMap(f)) {
|
580
|
+
upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
|
581
|
+
Map_InitFromValue(map, f, val, arena);
|
582
|
+
} else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
|
583
|
+
upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
|
584
|
+
RepeatedField_InitFromValue(arr, f, val, arena);
|
585
|
+
} else if (upb_FieldDef_IsSubMessage(f)) {
|
586
|
+
if (TYPE(val) == T_HASH) {
|
587
|
+
upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
|
588
|
+
Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena);
|
589
|
+
} else {
|
590
|
+
Message_setfield(msg, f, val, arena);
|
591
|
+
}
|
592
|
+
} else {
|
593
|
+
upb_MessageValue msgval =
|
594
|
+
Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
|
595
|
+
upb_Message_SetFieldByDef(msg, f, msgval, arena);
|
596
|
+
}
|
236
597
|
}
|
237
598
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
599
|
+
typedef struct {
|
600
|
+
upb_Message* msg;
|
601
|
+
const upb_MessageDef* msgdef;
|
602
|
+
upb_Arena* arena;
|
603
|
+
} MsgInit;
|
604
|
+
|
605
|
+
static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
606
|
+
MsgInit* msg_init = (MsgInit*)_self;
|
607
|
+
const char* name;
|
243
608
|
|
244
609
|
if (TYPE(key) == T_STRING) {
|
245
610
|
name = RSTRING_PTR(key);
|
@@ -247,48 +612,31 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
247
612
|
name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
|
248
613
|
} else {
|
249
614
|
rb_raise(rb_eArgError,
|
250
|
-
"Expected string or symbols as hash keys when initializing proto
|
615
|
+
"Expected string or symbols as hash keys when initializing proto "
|
616
|
+
"from hash.");
|
251
617
|
}
|
252
618
|
|
253
|
-
f =
|
619
|
+
const upb_FieldDef* f =
|
620
|
+
upb_MessageDef_FindFieldByName(msg_init->msgdef, name);
|
621
|
+
|
254
622
|
if (f == NULL) {
|
255
623
|
rb_raise(rb_eArgError,
|
256
624
|
"Unknown field name '%s' in initialization map entry.", name);
|
257
625
|
}
|
258
626
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
if (TYPE(val) != T_HASH) {
|
263
|
-
rb_raise(rb_eArgError,
|
264
|
-
"Expected Hash object as initializer value for map field '%s'.", name);
|
265
|
-
}
|
266
|
-
map = layout_get(self->descriptor->layout, Message_data(self), f);
|
267
|
-
Map_merge_into_self(map, val);
|
268
|
-
} else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
|
269
|
-
VALUE ary;
|
270
|
-
|
271
|
-
if (TYPE(val) != T_ARRAY) {
|
272
|
-
rb_raise(rb_eArgError,
|
273
|
-
"Expected array as initializer value for repeated field '%s'.", name);
|
274
|
-
}
|
275
|
-
ary = layout_get(self->descriptor->layout, Message_data(self), f);
|
276
|
-
for (int i = 0; i < RARRAY_LEN(val); i++) {
|
277
|
-
VALUE entry = rb_ary_entry(val, i);
|
278
|
-
if (TYPE(entry) == T_HASH && upb_fielddef_issubmsg(f)) {
|
279
|
-
entry = create_submsg_from_hash(f, entry);
|
280
|
-
}
|
627
|
+
Message_InitFieldFromValue(msg_init->msg, f, val, msg_init->arena);
|
628
|
+
return ST_CONTINUE;
|
629
|
+
}
|
281
630
|
|
282
|
-
|
283
|
-
|
631
|
+
void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
|
632
|
+
upb_Arena* arena) {
|
633
|
+
MsgInit msg_init = {msg, m, arena};
|
634
|
+
if (TYPE(val) == T_HASH) {
|
635
|
+
rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init);
|
284
636
|
} else {
|
285
|
-
|
286
|
-
|
287
|
-
}
|
288
|
-
|
289
|
-
layout_set(self->descriptor->layout, Message_data(self), f, val);
|
637
|
+
rb_raise(rb_eArgError, "Expected hash arguments or message, not %s",
|
638
|
+
rb_class2name(CLASS_OF(val)));
|
290
639
|
}
|
291
|
-
return 0;
|
292
640
|
}
|
293
641
|
|
294
642
|
/*
|
@@ -303,8 +651,14 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
|
303
651
|
* have been added to a pool. The method definitions described here on the
|
304
652
|
* Message class are provided on each concrete message class.
|
305
653
|
*/
|
306
|
-
VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
|
307
|
-
|
654
|
+
static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
|
655
|
+
Message* self = ruby_to_Message(_self);
|
656
|
+
VALUE arena_rb = Arena_new();
|
657
|
+
upb_Arena* arena = Arena_get(arena_rb);
|
658
|
+
upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
|
659
|
+
upb_Message* msg = upb_Message_New(t, arena);
|
660
|
+
|
661
|
+
Message_InitPtr(_self, msg, arena_rb);
|
308
662
|
|
309
663
|
if (argc == 0) {
|
310
664
|
return Qnil;
|
@@ -312,12 +666,7 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
|
|
312
666
|
if (argc != 1) {
|
313
667
|
rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
|
314
668
|
}
|
315
|
-
|
316
|
-
if (TYPE(hash_args) != T_HASH) {
|
317
|
-
rb_raise(rb_eArgError, "Expected hash arguments.");
|
318
|
-
}
|
319
|
-
|
320
|
-
rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
|
669
|
+
Message_InitFromValue((upb_Message*)self->msg, self->msgdef, argv[0], arena);
|
321
670
|
return Qnil;
|
322
671
|
}
|
323
672
|
|
@@ -327,37 +676,46 @@ VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
|
|
327
676
|
*
|
328
677
|
* Performs a shallow copy of this message and returns the new copy.
|
329
678
|
*/
|
330
|
-
VALUE Message_dup(VALUE _self) {
|
331
|
-
|
332
|
-
VALUE new_msg;
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
Message_data(new_msg_self),
|
341
|
-
Message_data(self));
|
342
|
-
|
679
|
+
static VALUE Message_dup(VALUE _self) {
|
680
|
+
Message* self = ruby_to_Message(_self);
|
681
|
+
VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
|
682
|
+
Message* new_msg_self = ruby_to_Message(new_msg);
|
683
|
+
size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
|
684
|
+
|
685
|
+
// TODO(copy unknown fields?)
|
686
|
+
// TODO(use official upb msg copy function)
|
687
|
+
memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
|
688
|
+
Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
|
343
689
|
return new_msg;
|
344
690
|
}
|
345
691
|
|
346
|
-
//
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
692
|
+
// Support function for Message_eq, and also used by other #eq functions.
|
693
|
+
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
694
|
+
const upb_MessageDef* m) {
|
695
|
+
if (m1 == m2) return true;
|
696
|
+
|
697
|
+
size_t size1, size2;
|
698
|
+
int encode_opts =
|
699
|
+
kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic;
|
700
|
+
upb_Arena* arena_tmp = upb_Arena_New();
|
701
|
+
const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
|
702
|
+
|
703
|
+
// Compare deterministically serialized payloads with no unknown fields.
|
704
|
+
char* data1;
|
705
|
+
char* data2;
|
706
|
+
upb_EncodeStatus status1 =
|
707
|
+
upb_Encode(m1, layout, encode_opts, arena_tmp, &data1, &size1);
|
708
|
+
upb_EncodeStatus status2 =
|
709
|
+
upb_Encode(m2, layout, encode_opts, arena_tmp, &data2, &size2);
|
710
|
+
|
711
|
+
if (status1 == kUpb_EncodeStatus_Ok && status2 == kUpb_EncodeStatus_Ok) {
|
712
|
+
bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
|
713
|
+
upb_Arena_Free(arena_tmp);
|
714
|
+
return ret;
|
715
|
+
} else {
|
716
|
+
upb_Arena_Free(arena_tmp);
|
717
|
+
rb_raise(cParseError, "Error comparing messages");
|
718
|
+
}
|
361
719
|
}
|
362
720
|
|
363
721
|
/*
|
@@ -369,22 +727,36 @@ VALUE Message_deep_copy(VALUE _self) {
|
|
369
727
|
* method's semantics (a more efficient comparison may actually be done if the
|
370
728
|
* field is of a primitive type).
|
371
729
|
*/
|
372
|
-
VALUE Message_eq(VALUE _self, VALUE _other) {
|
373
|
-
|
374
|
-
MessageHeader* other;
|
375
|
-
if (TYPE(_self) != TYPE(_other)) {
|
376
|
-
return Qfalse;
|
377
|
-
}
|
378
|
-
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
|
379
|
-
TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
|
730
|
+
static VALUE Message_eq(VALUE _self, VALUE _other) {
|
731
|
+
if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse;
|
380
732
|
|
381
|
-
|
382
|
-
|
383
|
-
|
733
|
+
Message* self = ruby_to_Message(_self);
|
734
|
+
Message* other = ruby_to_Message(_other);
|
735
|
+
assert(self->msgdef == other->msgdef);
|
736
|
+
|
737
|
+
return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
|
738
|
+
}
|
384
739
|
|
385
|
-
|
386
|
-
|
387
|
-
|
740
|
+
uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
741
|
+
uint64_t seed) {
|
742
|
+
upb_Arena* arena = upb_Arena_New();
|
743
|
+
char* data;
|
744
|
+
size_t size;
|
745
|
+
|
746
|
+
// Hash a deterministically serialized payloads with no unknown fields.
|
747
|
+
upb_EncodeStatus status = upb_Encode(
|
748
|
+
msg, upb_MessageDef_MiniTable(m),
|
749
|
+
kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena,
|
750
|
+
&data, &size);
|
751
|
+
|
752
|
+
if (status == kUpb_EncodeStatus_Ok) {
|
753
|
+
uint64_t ret = _upb_Hash(data, size, seed);
|
754
|
+
upb_Arena_Free(arena);
|
755
|
+
return ret;
|
756
|
+
} else {
|
757
|
+
upb_Arena_Free(arena);
|
758
|
+
rb_raise(cParseError, "Error calculating hash");
|
759
|
+
}
|
388
760
|
}
|
389
761
|
|
390
762
|
/*
|
@@ -393,11 +765,12 @@ VALUE Message_eq(VALUE _self, VALUE _other) {
|
|
393
765
|
*
|
394
766
|
* Returns a hash value that represents this message's field values.
|
395
767
|
*/
|
396
|
-
VALUE Message_hash(VALUE _self) {
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
768
|
+
static VALUE Message_hash(VALUE _self) {
|
769
|
+
Message* self = ruby_to_Message(_self);
|
770
|
+
uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0);
|
771
|
+
// RUBY_FIXNUM_MAX should be one less than a power of 2.
|
772
|
+
assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0);
|
773
|
+
return INT2FIX(hash_value & RUBY_FIXNUM_MAX);
|
401
774
|
}
|
402
775
|
|
403
776
|
/*
|
@@ -408,62 +781,129 @@ VALUE Message_hash(VALUE _self) {
|
|
408
781
|
* formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
|
409
782
|
* field's value is represented according to its own #inspect method.
|
410
783
|
*/
|
411
|
-
VALUE Message_inspect(VALUE _self) {
|
412
|
-
|
413
|
-
VALUE str;
|
414
|
-
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
|
784
|
+
static VALUE Message_inspect(VALUE _self) {
|
785
|
+
Message* self = ruby_to_Message(_self);
|
415
786
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
str = rb_str_cat2(str, ">");
|
422
|
-
return str;
|
787
|
+
StringBuilder* builder = StringBuilder_New();
|
788
|
+
Message_PrintMessage(builder, self->msg, self->msgdef);
|
789
|
+
VALUE ret = StringBuilder_ToRubyString(builder);
|
790
|
+
StringBuilder_Free(builder);
|
791
|
+
return ret;
|
423
792
|
}
|
424
793
|
|
425
|
-
|
426
|
-
|
427
|
-
*
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
794
|
+
// Support functions for Message_to_h //////////////////////////////////////////
|
795
|
+
|
796
|
+
static VALUE RepeatedField_CreateArray(const upb_Array* arr,
|
797
|
+
TypeInfo type_info) {
|
798
|
+
int size = arr ? upb_Array_Size(arr) : 0;
|
799
|
+
VALUE ary = rb_ary_new2(size);
|
800
|
+
|
801
|
+
for (int i = 0; i < size; i++) {
|
802
|
+
upb_MessageValue msgval = upb_Array_Get(arr, i);
|
803
|
+
VALUE val = Scalar_CreateHash(msgval, type_info);
|
804
|
+
rb_ary_push(ary, val);
|
805
|
+
}
|
806
|
+
|
807
|
+
return ary;
|
808
|
+
}
|
809
|
+
|
810
|
+
static VALUE Message_CreateHash(const upb_Message* msg,
|
811
|
+
const upb_MessageDef* m) {
|
812
|
+
if (!msg) return Qnil;
|
813
|
+
|
814
|
+
VALUE hash = rb_hash_new();
|
815
|
+
int n = upb_MessageDef_FieldCount(m);
|
816
|
+
bool is_proto2;
|
817
|
+
|
818
|
+
// We currently have a few behaviors that are specific to proto2.
|
819
|
+
// This is unfortunate, we should key behaviors off field attributes (like
|
820
|
+
// whether a field has presence), not proto2 vs. proto3. We should see if we
|
821
|
+
// can change this without breaking users.
|
822
|
+
is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
|
823
|
+
|
824
|
+
for (int i = 0; i < n; i++) {
|
825
|
+
const upb_FieldDef* field = upb_MessageDef_Field(m, i);
|
826
|
+
TypeInfo type_info = TypeInfo_get(field);
|
827
|
+
upb_MessageValue msgval;
|
828
|
+
VALUE msg_value;
|
829
|
+
VALUE msg_key;
|
830
|
+
|
831
|
+
if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
|
832
|
+
!upb_FieldDef_IsRepeated(field) &&
|
833
|
+
!upb_Message_HasFieldByDef(msg, field)) {
|
834
|
+
// TODO: Legacy behavior, remove when we fix the is_proto2 differences.
|
835
|
+
msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
|
836
|
+
rb_hash_aset(hash, msg_key, Qnil);
|
837
|
+
continue;
|
838
|
+
}
|
839
|
+
|
840
|
+
// Do not include fields that are not present (oneof or optional fields).
|
841
|
+
if (is_proto2 && upb_FieldDef_HasPresence(field) &&
|
842
|
+
!upb_Message_HasFieldByDef(msg, field)) {
|
843
|
+
continue;
|
844
|
+
}
|
845
|
+
|
846
|
+
msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
|
847
|
+
msgval = upb_Message_GetFieldByDef(msg, field);
|
848
|
+
|
849
|
+
// Proto2 omits empty map/repeated filds also.
|
850
|
+
|
851
|
+
if (upb_FieldDef_IsMap(field)) {
|
852
|
+
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
|
853
|
+
const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
|
854
|
+
const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
|
855
|
+
upb_CType key_type = upb_FieldDef_CType(key_f);
|
856
|
+
msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f));
|
857
|
+
} else if (upb_FieldDef_IsRepeated(field)) {
|
858
|
+
if (is_proto2 &&
|
859
|
+
(!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
|
860
|
+
continue;
|
456
861
|
}
|
457
|
-
|
458
|
-
|
459
|
-
msg_value =
|
862
|
+
msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
|
863
|
+
} else {
|
864
|
+
msg_value = Scalar_CreateHash(msgval, type_info);
|
460
865
|
}
|
866
|
+
|
461
867
|
rb_hash_aset(hash, msg_key, msg_value);
|
462
868
|
}
|
869
|
+
|
463
870
|
return hash;
|
464
871
|
}
|
465
872
|
|
873
|
+
VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
|
874
|
+
if (type_info.type == kUpb_CType_Message) {
|
875
|
+
return Message_CreateHash(msgval.msg_val, type_info.def.msgdef);
|
876
|
+
} else {
|
877
|
+
return Convert_UpbToRuby(msgval, type_info, Qnil);
|
878
|
+
}
|
879
|
+
}
|
466
880
|
|
881
|
+
/*
|
882
|
+
* call-seq:
|
883
|
+
* Message.to_h => {}
|
884
|
+
*
|
885
|
+
* Returns the message as a Ruby Hash object, with keys as symbols.
|
886
|
+
*/
|
887
|
+
static VALUE Message_to_h(VALUE _self) {
|
888
|
+
Message* self = ruby_to_Message(_self);
|
889
|
+
return Message_CreateHash(self->msg, self->msgdef);
|
890
|
+
}
|
891
|
+
|
892
|
+
/*
|
893
|
+
* call-seq:
|
894
|
+
* Message.freeze => self
|
895
|
+
*
|
896
|
+
* Freezes the message object. We have to intercept this so we can pin the
|
897
|
+
* Ruby object into memory so we don't forget it's frozen.
|
898
|
+
*/
|
899
|
+
static VALUE Message_freeze(VALUE _self) {
|
900
|
+
Message* self = ruby_to_Message(_self);
|
901
|
+
if (!RB_OBJ_FROZEN(_self)) {
|
902
|
+
Arena_Pin(self->arena, _self);
|
903
|
+
RB_OBJ_FREEZE(_self);
|
904
|
+
}
|
905
|
+
return _self;
|
906
|
+
}
|
467
907
|
|
468
908
|
/*
|
469
909
|
* call-seq:
|
@@ -472,16 +912,18 @@ VALUE Message_to_h(VALUE _self) {
|
|
472
912
|
* Accesses a field's value by field name. The provided field name should be a
|
473
913
|
* string.
|
474
914
|
*/
|
475
|
-
VALUE Message_index(VALUE _self, VALUE field_name) {
|
476
|
-
|
477
|
-
const
|
478
|
-
|
915
|
+
static VALUE Message_index(VALUE _self, VALUE field_name) {
|
916
|
+
Message* self = ruby_to_Message(_self);
|
917
|
+
const upb_FieldDef* field;
|
918
|
+
|
479
919
|
Check_Type(field_name, T_STRING);
|
480
|
-
field =
|
920
|
+
field = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
|
921
|
+
|
481
922
|
if (field == NULL) {
|
482
923
|
return Qnil;
|
483
924
|
}
|
484
|
-
|
925
|
+
|
926
|
+
return Message_getfield(_self, field);
|
485
927
|
}
|
486
928
|
|
487
929
|
/*
|
@@ -491,19 +933,269 @@ VALUE Message_index(VALUE _self, VALUE field_name) {
|
|
491
933
|
* Sets a field's value by field name. The provided field name should be a
|
492
934
|
* string.
|
493
935
|
*/
|
494
|
-
VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
|
495
|
-
|
496
|
-
const
|
497
|
-
|
936
|
+
static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
|
937
|
+
Message* self = ruby_to_Message(_self);
|
938
|
+
const upb_FieldDef* f;
|
939
|
+
upb_MessageValue val;
|
940
|
+
upb_Arena* arena = Arena_get(self->arena);
|
941
|
+
|
498
942
|
Check_Type(field_name, T_STRING);
|
499
|
-
|
500
|
-
|
943
|
+
f = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
|
944
|
+
|
945
|
+
if (f == NULL) {
|
501
946
|
rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
|
502
947
|
}
|
503
|
-
|
948
|
+
|
949
|
+
val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
|
950
|
+
upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
|
951
|
+
|
504
952
|
return Qnil;
|
505
953
|
}
|
506
954
|
|
955
|
+
/*
|
956
|
+
* call-seq:
|
957
|
+
* MessageClass.decode(data, options) => message
|
958
|
+
*
|
959
|
+
* Decodes the given data (as a string containing bytes in protocol buffers wire
|
960
|
+
* format) under the interpretration given by this message class's definition
|
961
|
+
* and returns a message object with the corresponding field values.
|
962
|
+
* @param options [Hash] options for the decoder
|
963
|
+
* recursion_limit: set to maximum decoding depth for message (default is 64)
|
964
|
+
*/
|
965
|
+
static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) {
|
966
|
+
VALUE data = argv[0];
|
967
|
+
int options = 0;
|
968
|
+
|
969
|
+
if (argc < 1 || argc > 2) {
|
970
|
+
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
971
|
+
}
|
972
|
+
|
973
|
+
if (argc == 2) {
|
974
|
+
VALUE hash_args = argv[1];
|
975
|
+
if (TYPE(hash_args) != T_HASH) {
|
976
|
+
rb_raise(rb_eArgError, "Expected hash arguments.");
|
977
|
+
}
|
978
|
+
|
979
|
+
VALUE depth =
|
980
|
+
rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
|
981
|
+
|
982
|
+
if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
|
983
|
+
options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
|
984
|
+
}
|
985
|
+
}
|
986
|
+
|
987
|
+
if (TYPE(data) != T_STRING) {
|
988
|
+
rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
|
989
|
+
}
|
990
|
+
|
991
|
+
VALUE msg_rb = initialize_rb_class_with_no_args(klass);
|
992
|
+
Message* msg = ruby_to_Message(msg_rb);
|
993
|
+
|
994
|
+
upb_DecodeStatus status =
|
995
|
+
upb_Decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
|
996
|
+
upb_MessageDef_MiniTable(msg->msgdef), NULL, options,
|
997
|
+
Arena_get(msg->arena));
|
998
|
+
|
999
|
+
if (status != kUpb_DecodeStatus_Ok) {
|
1000
|
+
rb_raise(cParseError, "Error occurred during parsing");
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
return msg_rb;
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
/*
|
1007
|
+
* call-seq:
|
1008
|
+
* MessageClass.decode_json(data, options = {}) => message
|
1009
|
+
*
|
1010
|
+
* Decodes the given data (as a string containing bytes in protocol buffers wire
|
1011
|
+
* format) under the interpretration given by this message class's definition
|
1012
|
+
* and returns a message object with the corresponding field values.
|
1013
|
+
*
|
1014
|
+
* @param options [Hash] options for the decoder
|
1015
|
+
* ignore_unknown_fields: set true to ignore unknown fields (default is to
|
1016
|
+
* raise an error)
|
1017
|
+
*/
|
1018
|
+
static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
|
1019
|
+
VALUE data = argv[0];
|
1020
|
+
int options = 0;
|
1021
|
+
upb_Status status;
|
1022
|
+
|
1023
|
+
// TODO(haberman): use this message's pool instead.
|
1024
|
+
const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
|
1025
|
+
|
1026
|
+
if (argc < 1 || argc > 2) {
|
1027
|
+
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
if (argc == 2) {
|
1031
|
+
VALUE hash_args = argv[1];
|
1032
|
+
if (TYPE(hash_args) != T_HASH) {
|
1033
|
+
rb_raise(rb_eArgError, "Expected hash arguments.");
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
if (RTEST(rb_hash_lookup2(
|
1037
|
+
hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) {
|
1038
|
+
options |= upb_JsonDecode_IgnoreUnknown;
|
1039
|
+
}
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
if (TYPE(data) != T_STRING) {
|
1043
|
+
rb_raise(rb_eArgError, "Expected string for JSON data.");
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
// TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
|
1047
|
+
// convert, because string handlers pass data directly to message string
|
1048
|
+
// fields.
|
1049
|
+
|
1050
|
+
VALUE msg_rb = initialize_rb_class_with_no_args(klass);
|
1051
|
+
Message* msg = ruby_to_Message(msg_rb);
|
1052
|
+
|
1053
|
+
// We don't allow users to decode a wrapper type directly.
|
1054
|
+
if (IsWrapper(msg->msgdef)) {
|
1055
|
+
rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly.");
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
upb_Status_Clear(&status);
|
1059
|
+
if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
|
1060
|
+
(upb_Message*)msg->msg, msg->msgdef, symtab, options,
|
1061
|
+
Arena_get(msg->arena), &status)) {
|
1062
|
+
rb_raise(cParseError, "Error occurred during parsing: %s",
|
1063
|
+
upb_Status_ErrorMessage(&status));
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
return msg_rb;
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
/*
|
1070
|
+
* call-seq:
|
1071
|
+
* MessageClass.encode(msg, options) => bytes
|
1072
|
+
*
|
1073
|
+
* Encodes the given message object to its serialized form in protocol buffers
|
1074
|
+
* wire format.
|
1075
|
+
* @param options [Hash] options for the encoder
|
1076
|
+
* recursion_limit: set to maximum encoding depth for message (default is 64)
|
1077
|
+
*/
|
1078
|
+
static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
|
1079
|
+
Message* msg = ruby_to_Message(argv[0]);
|
1080
|
+
int options = 0;
|
1081
|
+
char* data;
|
1082
|
+
size_t size;
|
1083
|
+
|
1084
|
+
if (CLASS_OF(argv[0]) != klass) {
|
1085
|
+
rb_raise(rb_eArgError, "Message of wrong type.");
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
if (argc < 1 || argc > 2) {
|
1089
|
+
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
if (argc == 2) {
|
1093
|
+
VALUE hash_args = argv[1];
|
1094
|
+
if (TYPE(hash_args) != T_HASH) {
|
1095
|
+
rb_raise(rb_eArgError, "Expected hash arguments.");
|
1096
|
+
}
|
1097
|
+
VALUE depth =
|
1098
|
+
rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit")));
|
1099
|
+
|
1100
|
+
if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
|
1101
|
+
options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth));
|
1102
|
+
}
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
upb_Arena* arena = upb_Arena_New();
|
1106
|
+
|
1107
|
+
upb_EncodeStatus status =
|
1108
|
+
upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
|
1109
|
+
arena, &data, &size);
|
1110
|
+
|
1111
|
+
if (status == kUpb_EncodeStatus_Ok) {
|
1112
|
+
VALUE ret = rb_str_new(data, size);
|
1113
|
+
rb_enc_associate(ret, rb_ascii8bit_encoding());
|
1114
|
+
upb_Arena_Free(arena);
|
1115
|
+
return ret;
|
1116
|
+
} else {
|
1117
|
+
upb_Arena_Free(arena);
|
1118
|
+
rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)");
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
/*
|
1123
|
+
* call-seq:
|
1124
|
+
* MessageClass.encode_json(msg, options = {}) => json_string
|
1125
|
+
*
|
1126
|
+
* Encodes the given message object into its serialized JSON representation.
|
1127
|
+
* @param options [Hash] options for the decoder
|
1128
|
+
* preserve_proto_fieldnames: set true to use original fieldnames (default is
|
1129
|
+
* to camelCase) emit_defaults: set true to emit 0/false values (default is to
|
1130
|
+
* omit them)
|
1131
|
+
*/
|
1132
|
+
static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
1133
|
+
Message* msg = ruby_to_Message(argv[0]);
|
1134
|
+
int options = 0;
|
1135
|
+
char buf[1024];
|
1136
|
+
size_t size;
|
1137
|
+
upb_Status status;
|
1138
|
+
|
1139
|
+
// TODO(haberman): use this message's pool instead.
|
1140
|
+
const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
|
1141
|
+
|
1142
|
+
if (argc < 1 || argc > 2) {
|
1143
|
+
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
if (argc == 2) {
|
1147
|
+
VALUE hash_args = argv[1];
|
1148
|
+
if (TYPE(hash_args) != T_HASH) {
|
1149
|
+
if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1,
|
1150
|
+
rb_str_new2("to_h")))) {
|
1151
|
+
hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0);
|
1152
|
+
} else {
|
1153
|
+
rb_raise(rb_eArgError, "Expected hash arguments.");
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
if (RTEST(rb_hash_lookup2(hash_args,
|
1158
|
+
ID2SYM(rb_intern("preserve_proto_fieldnames")),
|
1159
|
+
Qfalse))) {
|
1160
|
+
options |= upb_JsonEncode_UseProtoNames;
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")),
|
1164
|
+
Qfalse))) {
|
1165
|
+
options |= upb_JsonEncode_EmitDefaults;
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
if (RTEST(rb_hash_lookup2(hash_args,
|
1169
|
+
ID2SYM(rb_intern("format_enums_as_integers")),
|
1170
|
+
Qfalse))) {
|
1171
|
+
options |= upb_JsonEncode_FormatEnumsAsIntegers;
|
1172
|
+
}
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
upb_Status_Clear(&status);
|
1176
|
+
size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
|
1177
|
+
sizeof(buf), &status);
|
1178
|
+
|
1179
|
+
if (!upb_Status_IsOk(&status)) {
|
1180
|
+
rb_raise(cParseError, "Error occurred during encoding: %s",
|
1181
|
+
upb_Status_ErrorMessage(&status));
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
VALUE ret;
|
1185
|
+
if (size >= sizeof(buf)) {
|
1186
|
+
char* buf2 = malloc(size + 1);
|
1187
|
+
upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
|
1188
|
+
&status);
|
1189
|
+
ret = rb_str_new(buf2, size);
|
1190
|
+
free(buf2);
|
1191
|
+
} else {
|
1192
|
+
ret = rb_str_new(buf, size);
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
rb_enc_associate(ret, rb_utf8_encoding());
|
1196
|
+
return ret;
|
1197
|
+
}
|
1198
|
+
|
507
1199
|
/*
|
508
1200
|
* call-seq:
|
509
1201
|
* Message.descriptor => descriptor
|
@@ -511,22 +1203,15 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
|
|
511
1203
|
* Class method that returns the Descriptor instance corresponding to this
|
512
1204
|
* message class's type.
|
513
1205
|
*/
|
514
|
-
VALUE Message_descriptor(VALUE klass) {
|
1206
|
+
static VALUE Message_descriptor(VALUE klass) {
|
515
1207
|
return rb_ivar_get(klass, descriptor_instancevar_interned);
|
516
1208
|
}
|
517
1209
|
|
518
|
-
VALUE build_class_from_descriptor(
|
519
|
-
const char
|
1210
|
+
VALUE build_class_from_descriptor(VALUE descriptor) {
|
1211
|
+
const char* name;
|
520
1212
|
VALUE klass;
|
521
1213
|
|
522
|
-
|
523
|
-
desc->layout = create_layout(desc->msgdef);
|
524
|
-
}
|
525
|
-
if (desc->fill_method == NULL) {
|
526
|
-
desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
|
527
|
-
}
|
528
|
-
|
529
|
-
name = upb_msgdef_fullname(desc->msgdef);
|
1214
|
+
name = upb_MessageDef_FullName(Descriptor_GetMsgDef(descriptor));
|
530
1215
|
if (name == NULL) {
|
531
1216
|
rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
|
532
1217
|
}
|
@@ -534,37 +1219,8 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
534
1219
|
klass = rb_define_class_id(
|
535
1220
|
// Docs say this parameter is ignored. User will assign return value to
|
536
1221
|
// their own toplevel constant class name.
|
537
|
-
rb_intern("Message"),
|
538
|
-
|
539
|
-
rb_ivar_set(klass, descriptor_instancevar_interned,
|
540
|
-
get_def_obj(desc->msgdef));
|
541
|
-
rb_define_alloc_func(klass, Message_alloc);
|
542
|
-
rb_require("google/protobuf/message_exts");
|
543
|
-
rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
|
544
|
-
rb_extend_object(
|
545
|
-
klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
|
546
|
-
|
547
|
-
rb_define_method(klass, "method_missing",
|
548
|
-
Message_method_missing, -1);
|
549
|
-
rb_define_method(klass, "respond_to_missing?",
|
550
|
-
Message_respond_to_missing, -1);
|
551
|
-
rb_define_method(klass, "initialize", Message_initialize, -1);
|
552
|
-
rb_define_method(klass, "dup", Message_dup, 0);
|
553
|
-
// Also define #clone so that we don't inherit Object#clone.
|
554
|
-
rb_define_method(klass, "clone", Message_dup, 0);
|
555
|
-
rb_define_method(klass, "==", Message_eq, 1);
|
556
|
-
rb_define_method(klass, "hash", Message_hash, 0);
|
557
|
-
rb_define_method(klass, "to_h", Message_to_h, 0);
|
558
|
-
rb_define_method(klass, "to_hash", Message_to_h, 0);
|
559
|
-
rb_define_method(klass, "inspect", Message_inspect, 0);
|
560
|
-
rb_define_method(klass, "[]", Message_index, 1);
|
561
|
-
rb_define_method(klass, "[]=", Message_index_set, 2);
|
562
|
-
rb_define_singleton_method(klass, "decode", Message_decode, 1);
|
563
|
-
rb_define_singleton_method(klass, "encode", Message_encode, 1);
|
564
|
-
rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
|
565
|
-
rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
|
566
|
-
rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
|
567
|
-
|
1222
|
+
rb_intern("Message"), cAbstractMessage);
|
1223
|
+
rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
|
568
1224
|
return klass;
|
569
1225
|
}
|
570
1226
|
|
@@ -575,16 +1231,15 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
|
|
575
1231
|
* This module method, provided on each generated enum module, looks up an enum
|
576
1232
|
* value by number and returns its name as a Ruby symbol, or nil if not found.
|
577
1233
|
*/
|
578
|
-
VALUE enum_lookup(VALUE self, VALUE number) {
|
1234
|
+
static VALUE enum_lookup(VALUE self, VALUE number) {
|
579
1235
|
int32_t num = NUM2INT(number);
|
580
1236
|
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
return Qnil;
|
1237
|
+
const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
|
1238
|
+
const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, num);
|
1239
|
+
if (ev) {
|
1240
|
+
return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
|
586
1241
|
} else {
|
587
|
-
return
|
1242
|
+
return Qnil;
|
588
1243
|
}
|
589
1244
|
}
|
590
1245
|
|
@@ -595,17 +1250,15 @@ VALUE enum_lookup(VALUE self, VALUE number) {
|
|
595
1250
|
* This module method, provided on each generated enum module, looks up an enum
|
596
1251
|
* value by name (as a Ruby symbol) and returns its name, or nil if not found.
|
597
1252
|
*/
|
598
|
-
VALUE enum_resolve(VALUE self, VALUE sym) {
|
1253
|
+
static VALUE enum_resolve(VALUE self, VALUE sym) {
|
599
1254
|
const char* name = rb_id2name(SYM2ID(sym));
|
600
1255
|
VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
if (!found) {
|
606
|
-
return Qnil;
|
1256
|
+
const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
|
1257
|
+
const upb_EnumValueDef* ev = upb_EnumDef_FindValueByName(e, name);
|
1258
|
+
if (ev) {
|
1259
|
+
return INT2NUM(upb_EnumValueDef_Number(ev));
|
607
1260
|
} else {
|
608
|
-
return
|
1261
|
+
return Qnil;
|
609
1262
|
}
|
610
1263
|
}
|
611
1264
|
|
@@ -616,52 +1269,166 @@ VALUE enum_resolve(VALUE self, VALUE sym) {
|
|
616
1269
|
* This module method, provided on each generated enum module, returns the
|
617
1270
|
* EnumDescriptor corresponding to this enum type.
|
618
1271
|
*/
|
619
|
-
VALUE enum_descriptor(VALUE self) {
|
1272
|
+
static VALUE enum_descriptor(VALUE self) {
|
620
1273
|
return rb_ivar_get(self, descriptor_instancevar_interned);
|
621
1274
|
}
|
622
1275
|
|
623
|
-
VALUE build_module_from_enumdesc(
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
for (
|
629
|
-
|
630
|
-
|
631
|
-
const char*
|
632
|
-
|
1276
|
+
VALUE build_module_from_enumdesc(VALUE _enumdesc) {
|
1277
|
+
const upb_EnumDef* e = EnumDescriptor_GetEnumDef(_enumdesc);
|
1278
|
+
VALUE mod = rb_define_module_id(rb_intern(upb_EnumDef_FullName(e)));
|
1279
|
+
|
1280
|
+
int n = upb_EnumDef_ValueCount(e);
|
1281
|
+
for (int i = 0; i < n; i++) {
|
1282
|
+
const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
|
1283
|
+
upb_Arena* arena = upb_Arena_New();
|
1284
|
+
const char* src_name = upb_EnumValueDef_Name(ev);
|
1285
|
+
char* name = upb_strdup2(src_name, strlen(src_name), arena);
|
1286
|
+
int32_t value = upb_EnumValueDef_Number(ev);
|
633
1287
|
if (name[0] < 'A' || name[0] > 'Z') {
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
1288
|
+
if (name[0] >= 'a' && name[0] <= 'z') {
|
1289
|
+
name[0] -= 32; // auto capitalize
|
1290
|
+
} else {
|
1291
|
+
rb_warn(
|
1292
|
+
"Enum value '%s' does not start with an uppercase letter "
|
1293
|
+
"as is required for Ruby constants.",
|
1294
|
+
name);
|
1295
|
+
}
|
638
1296
|
}
|
639
1297
|
rb_define_const(mod, name, INT2NUM(value));
|
1298
|
+
upb_Arena_Free(arena);
|
640
1299
|
}
|
641
1300
|
|
642
1301
|
rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
|
643
1302
|
rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
|
644
1303
|
rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
|
645
|
-
rb_ivar_set(mod, descriptor_instancevar_interned,
|
646
|
-
get_def_obj(enumdesc->enumdef));
|
1304
|
+
rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc);
|
647
1305
|
|
648
1306
|
return mod;
|
649
1307
|
}
|
650
1308
|
|
651
|
-
|
652
|
-
*
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
*
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
1309
|
+
// Internal to the library; used by Google::Protobuf.deep_copy.
|
1310
|
+
upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
|
1311
|
+
upb_Arena* arena) {
|
1312
|
+
// Serialize and parse.
|
1313
|
+
upb_Arena* tmp_arena = upb_Arena_New();
|
1314
|
+
const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
|
1315
|
+
size_t size;
|
1316
|
+
|
1317
|
+
upb_Message* new_msg = upb_Message_New(layout, arena);
|
1318
|
+
char* data;
|
1319
|
+
|
1320
|
+
if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
|
1321
|
+
kUpb_EncodeStatus_Ok ||
|
1322
|
+
upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
|
1323
|
+
kUpb_DecodeStatus_Ok) {
|
1324
|
+
upb_Arena_Free(tmp_arena);
|
1325
|
+
rb_raise(cParseError, "Error occurred copying proto");
|
1326
|
+
}
|
1327
|
+
|
1328
|
+
upb_Arena_Free(tmp_arena);
|
1329
|
+
return new_msg;
|
1330
|
+
}
|
1331
|
+
|
1332
|
+
const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
|
1333
|
+
const char* name, upb_Arena* arena) {
|
1334
|
+
if (value == Qnil) {
|
1335
|
+
rb_raise(cTypeError, "nil message not allowed here.");
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
VALUE klass = CLASS_OF(value);
|
1339
|
+
VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned);
|
1340
|
+
const upb_MessageDef* val_m =
|
1341
|
+
desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb);
|
1342
|
+
|
1343
|
+
if (val_m != m) {
|
1344
|
+
// Check for possible implicit conversions
|
1345
|
+
// TODO: hash conversion?
|
1346
|
+
|
1347
|
+
switch (upb_MessageDef_WellKnownType(m)) {
|
1348
|
+
case kUpb_WellKnown_Timestamp: {
|
1349
|
+
// Time -> Google::Protobuf::Timestamp
|
1350
|
+
const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
|
1351
|
+
upb_Message* msg = upb_Message_New(t, arena);
|
1352
|
+
upb_MessageValue sec, nsec;
|
1353
|
+
struct timespec time;
|
1354
|
+
const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
|
1355
|
+
const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
|
1356
|
+
|
1357
|
+
if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype;
|
1358
|
+
|
1359
|
+
time = rb_time_timespec(value);
|
1360
|
+
sec.int64_val = time.tv_sec;
|
1361
|
+
nsec.int32_val = time.tv_nsec;
|
1362
|
+
upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
|
1363
|
+
upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
|
1364
|
+
return msg;
|
1365
|
+
}
|
1366
|
+
case kUpb_WellKnown_Duration: {
|
1367
|
+
// Numeric -> Google::Protobuf::Duration
|
1368
|
+
const upb_MiniTable* t = upb_MessageDef_MiniTable(m);
|
1369
|
+
upb_Message* msg = upb_Message_New(t, arena);
|
1370
|
+
upb_MessageValue sec, nsec;
|
1371
|
+
const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1);
|
1372
|
+
const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2);
|
1373
|
+
|
1374
|
+
if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype;
|
1375
|
+
|
1376
|
+
sec.int64_val = NUM2LL(value);
|
1377
|
+
nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
|
1378
|
+
upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
|
1379
|
+
upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
|
1380
|
+
return msg;
|
1381
|
+
}
|
1382
|
+
default:
|
1383
|
+
badtype:
|
1384
|
+
rb_raise(cTypeError,
|
1385
|
+
"Invalid type %s to assign to submessage field '%s'.",
|
1386
|
+
rb_class2name(CLASS_OF(value)), name);
|
1387
|
+
}
|
666
1388
|
}
|
1389
|
+
|
1390
|
+
Message* self = ruby_to_Message(value);
|
1391
|
+
Arena_fuse(self->arena, arena);
|
1392
|
+
|
1393
|
+
return self->msg;
|
1394
|
+
}
|
1395
|
+
|
1396
|
+
static void Message_define_class(VALUE klass) {
|
1397
|
+
rb_define_alloc_func(klass, Message_alloc);
|
1398
|
+
|
1399
|
+
rb_require("google/protobuf/message_exts");
|
1400
|
+
rb_define_method(klass, "method_missing", Message_method_missing, -1);
|
1401
|
+
rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
|
1402
|
+
-1);
|
1403
|
+
rb_define_method(klass, "initialize", Message_initialize, -1);
|
1404
|
+
rb_define_method(klass, "dup", Message_dup, 0);
|
1405
|
+
// Also define #clone so that we don't inherit Object#clone.
|
1406
|
+
rb_define_method(klass, "clone", Message_dup, 0);
|
1407
|
+
rb_define_method(klass, "==", Message_eq, 1);
|
1408
|
+
rb_define_method(klass, "eql?", Message_eq, 1);
|
1409
|
+
rb_define_method(klass, "freeze", Message_freeze, 0);
|
1410
|
+
rb_define_method(klass, "hash", Message_hash, 0);
|
1411
|
+
rb_define_method(klass, "to_h", Message_to_h, 0);
|
1412
|
+
rb_define_method(klass, "inspect", Message_inspect, 0);
|
1413
|
+
rb_define_method(klass, "to_s", Message_inspect, 0);
|
1414
|
+
rb_define_method(klass, "[]", Message_index, 1);
|
1415
|
+
rb_define_method(klass, "[]=", Message_index_set, 2);
|
1416
|
+
rb_define_singleton_method(klass, "decode", Message_decode, -1);
|
1417
|
+
rb_define_singleton_method(klass, "encode", Message_encode, -1);
|
1418
|
+
rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1);
|
1419
|
+
rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
|
1420
|
+
rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
|
1421
|
+
}
|
1422
|
+
|
1423
|
+
void Message_register(VALUE protobuf) {
|
1424
|
+
cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
|
1425
|
+
cAbstractMessage =
|
1426
|
+
rb_define_class_under(protobuf, "AbstractMessage", rb_cObject);
|
1427
|
+
Message_define_class(cAbstractMessage);
|
1428
|
+
rb_gc_register_address(&cAbstractMessage);
|
1429
|
+
|
1430
|
+
// Ruby-interned string: "descriptor". We use this identifier to store an
|
1431
|
+
// instance variable on message classes we create in order to link them back
|
1432
|
+
// to their descriptors.
|
1433
|
+
descriptor_instancevar_interned = rb_intern("@descriptor");
|
667
1434
|
}
|