google-protobuf 3.25.8 → 4.28.2
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.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/convert.c +40 -15
- data/ext/google/protobuf_c/defs.c +365 -26
- data/ext/google/protobuf_c/extconf.rb +1 -1
- data/ext/google/protobuf_c/glue.c +16 -0
- data/ext/google/protobuf_c/map.c +72 -27
- data/ext/google/protobuf_c/map.h +7 -3
- data/ext/google/protobuf_c/message.c +100 -111
- data/ext/google/protobuf_c/message.h +2 -6
- data/ext/google/protobuf_c/protobuf.c +30 -15
- data/ext/google/protobuf_c/protobuf.h +3 -7
- data/ext/google/protobuf_c/repeated_field.c +58 -23
- data/ext/google/protobuf_c/repeated_field.h +6 -2
- data/ext/google/protobuf_c/ruby-upb.c +13047 -10862
- data/ext/google/protobuf_c/ruby-upb.h +11114 -9028
- data/ext/google/protobuf_c/shared_convert.c +7 -2
- data/ext/google/protobuf_c/shared_message.c +3 -32
- data/ext/google/protobuf_c/shared_message.h +0 -4
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
- data/lib/google/protobuf/any_pb.rb +1 -22
- data/lib/google/protobuf/api_pb.rb +1 -24
- data/lib/google/protobuf/descriptor_pb.rb +3 -23
- data/lib/google/protobuf/duration_pb.rb +1 -22
- data/lib/google/protobuf/empty_pb.rb +1 -22
- data/lib/google/protobuf/ffi/descriptor.rb +4 -4
- data/lib/google/protobuf/ffi/descriptor_pool.rb +3 -1
- data/lib/google/protobuf/ffi/enum_descriptor.rb +3 -1
- data/lib/google/protobuf/ffi/ffi.rb +3 -6
- data/lib/google/protobuf/ffi/field_descriptor.rb +13 -2
- data/lib/google/protobuf/ffi/file_descriptor.rb +3 -13
- data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
- data/lib/google/protobuf/ffi/internal/convert.rb +21 -30
- data/lib/google/protobuf/ffi/map.rb +50 -24
- data/lib/google/protobuf/ffi/message.rb +183 -64
- data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
- data/lib/google/protobuf/ffi/object_cache.rb +3 -3
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +3 -1
- data/lib/google/protobuf/ffi/repeated_field.rb +47 -19
- data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
- data/lib/google/protobuf/field_mask_pb.rb +1 -22
- data/lib/google/protobuf/internal/object_cache.rb +99 -0
- data/lib/google/protobuf/plugin_pb.rb +2 -24
- data/lib/google/protobuf/repeated_field.rb +4 -5
- data/lib/google/protobuf/source_context_pb.rb +1 -22
- data/lib/google/protobuf/struct_pb.rb +1 -22
- data/lib/google/protobuf/timestamp_pb.rb +1 -22
- data/lib/google/protobuf/type_pb.rb +1 -24
- data/lib/google/protobuf/wrappers_pb.rb +1 -22
- data/lib/google/protobuf.rb +1 -1
- data/lib/google/protobuf_ffi.rb +3 -2
- data/lib/google/protobuf_native.rb +0 -1
- data/lib/google/tasks/ffi.rake +1 -3
- metadata +25 -12
- data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
- data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
- data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
- data/lib/google/protobuf/descriptor_dsl.rb +0 -465
- data/lib/google/protobuf/object_cache.rb +0 -97
data/ext/google/protobuf_c/map.c
CHANGED
@@ -38,9 +38,11 @@ static void Map_mark(void* _self) {
|
|
38
38
|
rb_gc_mark(self->arena);
|
39
39
|
}
|
40
40
|
|
41
|
+
static size_t Map_memsize(const void* _self) { return sizeof(Map); }
|
42
|
+
|
41
43
|
const rb_data_type_t Map_type = {
|
42
44
|
"Google::Protobuf::Map",
|
43
|
-
{Map_mark, RUBY_DEFAULT_FREE,
|
45
|
+
{Map_mark, RUBY_DEFAULT_FREE, Map_memsize},
|
44
46
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
45
47
|
};
|
46
48
|
|
@@ -61,9 +63,10 @@ static VALUE Map_alloc(VALUE klass) {
|
|
61
63
|
return TypedData_Wrap_Struct(klass, &Map_type, self);
|
62
64
|
}
|
63
65
|
|
64
|
-
VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type,
|
65
|
-
VALUE arena) {
|
66
|
+
VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
|
67
|
+
TypeInfo value_type, VALUE arena) {
|
66
68
|
PBRUBY_ASSERT(map);
|
69
|
+
PBRUBY_ASSERT(arena != Qnil);
|
67
70
|
|
68
71
|
VALUE val = ObjectCache_Get(map);
|
69
72
|
|
@@ -81,7 +84,6 @@ VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
|
|
81
84
|
}
|
82
85
|
return ObjectCache_TryAdd(map, val);
|
83
86
|
}
|
84
|
-
|
85
87
|
return val;
|
86
88
|
}
|
87
89
|
|
@@ -103,8 +105,9 @@ static TypeInfo Map_keyinfo(Map* self) {
|
|
103
105
|
}
|
104
106
|
|
105
107
|
static upb_Map* Map_GetMutable(VALUE _self) {
|
106
|
-
|
107
|
-
|
108
|
+
const upb_Map* map = ruby_to_Map(_self)->map;
|
109
|
+
Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map));
|
110
|
+
return (upb_Map*)map;
|
108
111
|
}
|
109
112
|
|
110
113
|
VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
|
@@ -437,14 +440,14 @@ static VALUE Map_has_key(VALUE _self, VALUE key) {
|
|
437
440
|
* nil if none was present. Throws an exception if the key is of the wrong type.
|
438
441
|
*/
|
439
442
|
static VALUE Map_delete(VALUE _self, VALUE key) {
|
443
|
+
upb_Map* map = Map_GetMutable(_self);
|
440
444
|
Map* self = ruby_to_Map(_self);
|
441
|
-
rb_check_frozen(_self);
|
442
445
|
|
443
446
|
upb_MessageValue key_upb =
|
444
447
|
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
445
448
|
upb_MessageValue val_upb;
|
446
449
|
|
447
|
-
if (upb_Map_Delete(
|
450
|
+
if (upb_Map_Delete(map, key_upb, &val_upb)) {
|
448
451
|
return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
|
449
452
|
} else {
|
450
453
|
return Qnil;
|
@@ -558,40 +561,81 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
558
561
|
|
559
562
|
/*
|
560
563
|
* call-seq:
|
561
|
-
*
|
564
|
+
* Map.frozen? => bool
|
562
565
|
*
|
563
|
-
*
|
564
|
-
* Ruby object
|
566
|
+
* Returns true if the map is frozen in either Ruby or the underlying
|
567
|
+
* representation. Freezes the Ruby map object if it is not already frozen in
|
568
|
+
* Ruby but it is frozen in the underlying representation.
|
565
569
|
*/
|
566
|
-
|
570
|
+
VALUE Map_frozen(VALUE _self) {
|
567
571
|
Map* self = ruby_to_Map(_self);
|
568
|
-
if (!
|
569
|
-
|
570
|
-
|
572
|
+
if (!upb_Map_IsFrozen(self->map)) {
|
573
|
+
PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
|
574
|
+
return Qfalse;
|
571
575
|
}
|
572
|
-
|
576
|
+
|
577
|
+
// Lazily freeze the Ruby wrapper.
|
578
|
+
if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
|
579
|
+
return Qtrue;
|
573
580
|
}
|
574
581
|
|
575
582
|
/*
|
576
|
-
*
|
577
|
-
*
|
583
|
+
* call-seq:
|
584
|
+
* Map.freeze => self
|
585
|
+
*
|
586
|
+
* Freezes the map object. We have to intercept this so we can freeze the
|
587
|
+
* underlying representation, not just the Ruby wrapper.
|
578
588
|
*/
|
579
|
-
VALUE
|
589
|
+
VALUE Map_freeze(VALUE _self) {
|
580
590
|
Map* self = ruby_to_Map(_self);
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
591
|
+
if (RB_OBJ_FROZEN(_self)) {
|
592
|
+
PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
|
593
|
+
return _self;
|
594
|
+
}
|
585
595
|
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
596
|
+
if (!upb_Map_IsFrozen(self->map)) {
|
597
|
+
if (self->value_type_info.type == kUpb_CType_Message) {
|
598
|
+
upb_Map_Freeze(
|
599
|
+
Map_GetMutable(_self),
|
600
|
+
upb_MessageDef_MiniTable(self->value_type_info.def.msgdef));
|
601
|
+
} else {
|
602
|
+
upb_Map_Freeze(Map_GetMutable(_self), NULL);
|
590
603
|
}
|
591
604
|
}
|
605
|
+
|
606
|
+
RB_OBJ_FREEZE(_self);
|
607
|
+
|
592
608
|
return _self;
|
593
609
|
}
|
594
610
|
|
611
|
+
VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
|
612
|
+
PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
|
613
|
+
VALUE val = ObjectCache_Get(f);
|
614
|
+
|
615
|
+
if (val == Qnil) {
|
616
|
+
const upb_FieldDef* key_f = map_field_key(f);
|
617
|
+
const upb_FieldDef* val_f = map_field_value(f);
|
618
|
+
upb_CType key_type = upb_FieldDef_CType(key_f);
|
619
|
+
TypeInfo value_type_info = TypeInfo_get(val_f);
|
620
|
+
val = Map_alloc(cMap);
|
621
|
+
Map* self;
|
622
|
+
TypedData_Get_Struct(val, Map, &Map_type, self);
|
623
|
+
self->arena = Arena_new();
|
624
|
+
self->map =
|
625
|
+
upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type);
|
626
|
+
self->key_type = key_type;
|
627
|
+
self->value_type_info = value_type_info;
|
628
|
+
if (self->value_type_info.type == kUpb_CType_Message) {
|
629
|
+
const upb_MessageDef* val_m = value_type_info.def.msgdef;
|
630
|
+
self->value_type_class = Descriptor_DefToClass(val_m);
|
631
|
+
}
|
632
|
+
return ObjectCache_TryAdd(f, Map_freeze(val));
|
633
|
+
}
|
634
|
+
PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
|
635
|
+
PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
|
636
|
+
return val;
|
637
|
+
}
|
638
|
+
|
595
639
|
/*
|
596
640
|
* call-seq:
|
597
641
|
* Map.hash => hash_value
|
@@ -678,6 +722,7 @@ void Map_register(VALUE module) {
|
|
678
722
|
rb_define_method(klass, "clone", Map_dup, 0);
|
679
723
|
rb_define_method(klass, "==", Map_eq, 1);
|
680
724
|
rb_define_method(klass, "freeze", Map_freeze, 0);
|
725
|
+
rb_define_method(klass, "frozen?", Map_frozen, 0);
|
681
726
|
rb_define_method(klass, "hash", Map_hash, 0);
|
682
727
|
rb_define_method(klass, "to_h", Map_to_h, 0);
|
683
728
|
rb_define_method(klass, "inspect", Map_inspect, 0);
|
data/ext/google/protobuf_c/map.h
CHANGED
@@ -11,10 +11,14 @@
|
|
11
11
|
#include "protobuf.h"
|
12
12
|
#include "ruby-upb.h"
|
13
13
|
|
14
|
+
// Returns a frozen sentinel Ruby wrapper object for an empty upb_Map with the
|
15
|
+
// key and value types specified by the field. Creates one if it doesn't exist.
|
16
|
+
VALUE Map_EmptyFrozen(const upb_FieldDef* f);
|
17
|
+
|
14
18
|
// Returns a Ruby wrapper object for the given map, which will be created if
|
15
19
|
// one does not exist already.
|
16
|
-
VALUE Map_GetRubyWrapper(upb_Map *map, upb_CType key_type,
|
17
|
-
VALUE arena);
|
20
|
+
VALUE Map_GetRubyWrapper(const upb_Map *map, upb_CType key_type,
|
21
|
+
TypeInfo value_type, VALUE arena);
|
18
22
|
|
19
23
|
// Gets the underlying upb_Map for this Ruby map object, which must have
|
20
24
|
// key/value type that match |field|. If this is not a map or the type doesn't
|
@@ -39,6 +43,6 @@ extern VALUE cMap;
|
|
39
43
|
void Map_register(VALUE module);
|
40
44
|
|
41
45
|
// Recursively freeze map
|
42
|
-
VALUE
|
46
|
+
VALUE Map_freeze(VALUE _self);
|
43
47
|
|
44
48
|
#endif // RUBY_PROTOBUF_MAP_H_
|
@@ -44,9 +44,11 @@ static void Message_mark(void* _self) {
|
|
44
44
|
rb_gc_mark(self->arena);
|
45
45
|
}
|
46
46
|
|
47
|
+
static size_t Message_memsize(const void* _self) { return sizeof(Message); }
|
48
|
+
|
47
49
|
static rb_data_type_t Message_type = {
|
48
50
|
"Google::Protobuf::Message",
|
49
|
-
{Message_mark, RUBY_DEFAULT_FREE,
|
51
|
+
{Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
|
50
52
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
51
53
|
};
|
52
54
|
|
@@ -78,11 +80,13 @@ const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
|
|
78
80
|
}
|
79
81
|
|
80
82
|
upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
|
81
|
-
|
82
|
-
|
83
|
+
const upb_Message* upb_msg = Message_Get(msg_rb, m);
|
84
|
+
Protobuf_CheckNotFrozen(msg_rb, upb_Message_IsFrozen(upb_msg));
|
85
|
+
return (upb_Message*)upb_msg;
|
83
86
|
}
|
84
87
|
|
85
|
-
void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
|
88
|
+
void Message_InitPtr(VALUE self_, const upb_Message* msg, VALUE arena) {
|
89
|
+
PBRUBY_ASSERT(arena != Qnil);
|
86
90
|
Message* self = ruby_to_Message(self_);
|
87
91
|
self->msg = msg;
|
88
92
|
RB_OBJ_WRITE(self_, &self->arena, arena);
|
@@ -103,7 +107,7 @@ void Message_CheckClass(VALUE klass) {
|
|
103
107
|
}
|
104
108
|
}
|
105
109
|
|
106
|
-
VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
110
|
+
VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
|
107
111
|
VALUE arena) {
|
108
112
|
if (msg == NULL) return Qnil;
|
109
113
|
|
@@ -114,7 +118,6 @@ VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
|
114
118
|
val = Message_alloc(klass);
|
115
119
|
Message_InitPtr(val, msg, arena);
|
116
120
|
}
|
117
|
-
|
118
121
|
return val;
|
119
122
|
}
|
120
123
|
|
@@ -246,7 +249,7 @@ static int extract_method_call(VALUE method_name, Message* self,
|
|
246
249
|
static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
|
247
250
|
int accessor_type) {
|
248
251
|
Message* self = ruby_to_Message(_self);
|
249
|
-
const upb_FieldDef* oneof_field =
|
252
|
+
const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o);
|
250
253
|
|
251
254
|
switch (accessor_type) {
|
252
255
|
case METHOD_PRESENCE:
|
@@ -286,13 +289,42 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
|
|
286
289
|
upb_Message_SetFieldByDef(msg, f, msgval, arena);
|
287
290
|
}
|
288
291
|
|
292
|
+
VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f,
|
293
|
+
VALUE arena) {
|
294
|
+
upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
|
295
|
+
if (upb_FieldDef_IsMap(f)) {
|
296
|
+
if (msgval.map_val == NULL) {
|
297
|
+
return Map_EmptyFrozen(f);
|
298
|
+
}
|
299
|
+
const upb_FieldDef* key_f = map_field_key(f);
|
300
|
+
const upb_FieldDef* val_f = map_field_value(f);
|
301
|
+
upb_CType key_type = upb_FieldDef_CType(key_f);
|
302
|
+
TypeInfo value_type_info = TypeInfo_get(val_f);
|
303
|
+
return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, arena);
|
304
|
+
}
|
305
|
+
if (upb_FieldDef_IsRepeated(f)) {
|
306
|
+
if (msgval.array_val == NULL) {
|
307
|
+
return RepeatedField_EmptyFrozen(f);
|
308
|
+
}
|
309
|
+
return RepeatedField_GetRubyWrapper(msgval.array_val, TypeInfo_get(f),
|
310
|
+
arena);
|
311
|
+
}
|
312
|
+
VALUE ret;
|
313
|
+
if (upb_FieldDef_IsSubMessage(f)) {
|
314
|
+
const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
|
315
|
+
ret = Message_GetRubyWrapper(msgval.msg_val, m, arena);
|
316
|
+
} else {
|
317
|
+
ret = Convert_UpbToRuby(msgval, TypeInfo_get(f), Qnil);
|
318
|
+
}
|
319
|
+
return ret;
|
320
|
+
}
|
321
|
+
|
289
322
|
VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
|
290
323
|
Message* self = ruby_to_Message(_self);
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
upb_Message* msg = (upb_Message*)self->msg;
|
324
|
+
if (upb_Message_IsFrozen(self->msg)) {
|
325
|
+
return Message_getfield_frozen(self->msg, f, self->arena);
|
326
|
+
}
|
327
|
+
upb_Message* msg = Message_GetMutable(_self, NULL);
|
296
328
|
upb_Arena* arena = Arena_get(self->arena);
|
297
329
|
if (upb_FieldDef_IsMap(f)) {
|
298
330
|
upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
|
@@ -305,12 +337,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
|
|
305
337
|
upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
|
306
338
|
return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
|
307
339
|
} else if (upb_FieldDef_IsSubMessage(f)) {
|
308
|
-
if (!upb_Message_HasFieldByDef(
|
340
|
+
if (!upb_Message_HasFieldByDef(msg, f)) return Qnil;
|
309
341
|
upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
|
310
342
|
const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
|
311
343
|
return Message_GetRubyWrapper(submsg, m, self->arena);
|
312
344
|
} else {
|
313
|
-
upb_MessageValue msgval = upb_Message_GetFieldByDef(
|
345
|
+
upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
|
314
346
|
return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
|
315
347
|
}
|
316
348
|
}
|
@@ -434,7 +466,6 @@ static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
|
|
434
466
|
if (argc != 2) {
|
435
467
|
rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc);
|
436
468
|
}
|
437
|
-
rb_check_frozen(_self);
|
438
469
|
break;
|
439
470
|
default:
|
440
471
|
if (argc != 1) {
|
@@ -661,29 +692,12 @@ static VALUE Message_dup(VALUE _self) {
|
|
661
692
|
Message* self = ruby_to_Message(_self);
|
662
693
|
VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
|
663
694
|
Message* new_msg_self = ruby_to_Message(new_msg);
|
664
|
-
|
665
|
-
|
666
|
-
// TODO
|
667
|
-
// TODO
|
668
|
-
memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
|
695
|
+
const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
|
696
|
+
upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m);
|
669
697
|
Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
|
670
698
|
return new_msg;
|
671
699
|
}
|
672
700
|
|
673
|
-
// Support function for Message_eq, and also used by other #eq functions.
|
674
|
-
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
675
|
-
const upb_MessageDef* m) {
|
676
|
-
upb_Status status;
|
677
|
-
upb_Status_Clear(&status);
|
678
|
-
bool return_value = shared_Message_Equal(m1, m2, m, &status);
|
679
|
-
if (upb_Status_IsOk(&status)) {
|
680
|
-
return return_value;
|
681
|
-
} else {
|
682
|
-
rb_raise(cParseError, "Message_Equal(): %s",
|
683
|
-
upb_Status_ErrorMessage(&status));
|
684
|
-
}
|
685
|
-
}
|
686
|
-
|
687
701
|
/*
|
688
702
|
* call-seq:
|
689
703
|
* Message.==(other) => boolean
|
@@ -700,7 +714,10 @@ static VALUE Message_eq(VALUE _self, VALUE _other) {
|
|
700
714
|
Message* other = ruby_to_Message(_other);
|
701
715
|
assert(self->msgdef == other->msgdef);
|
702
716
|
|
703
|
-
|
717
|
+
const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef);
|
718
|
+
const int options = 0;
|
719
|
+
return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue
|
720
|
+
: Qfalse;
|
704
721
|
}
|
705
722
|
|
706
723
|
uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
@@ -769,58 +786,34 @@ static VALUE Message_CreateHash(const upb_Message* msg,
|
|
769
786
|
if (!msg) return Qnil;
|
770
787
|
|
771
788
|
VALUE hash = rb_hash_new();
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
// This is unfortunate, we should key behaviors off field attributes (like
|
777
|
-
// whether a field has presence), not proto2 vs. proto3. We should see if we
|
778
|
-
// can change this without breaking users.
|
779
|
-
is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
|
780
|
-
|
781
|
-
for (int i = 0; i < n; i++) {
|
782
|
-
const upb_FieldDef* field = upb_MessageDef_Field(m, i);
|
783
|
-
TypeInfo type_info = TypeInfo_get(field);
|
784
|
-
upb_MessageValue msgval;
|
785
|
-
VALUE msg_value;
|
786
|
-
VALUE msg_key;
|
787
|
-
|
788
|
-
if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
|
789
|
-
!upb_FieldDef_IsRepeated(field) &&
|
790
|
-
!upb_Message_HasFieldByDef(msg, field)) {
|
791
|
-
// TODO: Legacy behavior, remove when we fix the is_proto2 differences.
|
792
|
-
msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
|
793
|
-
rb_hash_aset(hash, msg_key, Qnil);
|
794
|
-
continue;
|
795
|
-
}
|
789
|
+
size_t iter = kUpb_Message_Begin;
|
790
|
+
const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m));
|
791
|
+
const upb_FieldDef* field;
|
792
|
+
upb_MessageValue val;
|
796
793
|
|
797
|
-
|
798
|
-
if (
|
799
|
-
|
794
|
+
while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) {
|
795
|
+
if (upb_FieldDef_IsExtension(field)) {
|
796
|
+
// TODO: allow extensions once we have decided what naming scheme the
|
797
|
+
// symbol should use. eg. :"[pkg.ext]"
|
800
798
|
continue;
|
801
799
|
}
|
802
800
|
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
// Proto2 omits empty map/repeated filds also.
|
801
|
+
TypeInfo type_info = TypeInfo_get(field);
|
802
|
+
VALUE msg_value;
|
807
803
|
|
808
804
|
if (upb_FieldDef_IsMap(field)) {
|
809
805
|
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
|
810
806
|
const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
|
811
807
|
const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
|
812
808
|
upb_CType key_type = upb_FieldDef_CType(key_f);
|
813
|
-
msg_value = Map_CreateHash(
|
809
|
+
msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f));
|
814
810
|
} else if (upb_FieldDef_IsRepeated(field)) {
|
815
|
-
|
816
|
-
(!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
|
817
|
-
continue;
|
818
|
-
}
|
819
|
-
msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
|
811
|
+
msg_value = RepeatedField_CreateArray(val.array_val, type_info);
|
820
812
|
} else {
|
821
|
-
msg_value = Scalar_CreateHash(
|
813
|
+
msg_value = Scalar_CreateHash(val, type_info);
|
822
814
|
}
|
823
815
|
|
816
|
+
VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
|
824
817
|
rb_hash_aset(hash, msg_key, msg_value);
|
825
818
|
}
|
826
819
|
|
@@ -848,43 +841,42 @@ static VALUE Message_to_h(VALUE _self) {
|
|
848
841
|
|
849
842
|
/*
|
850
843
|
* call-seq:
|
851
|
-
* Message.
|
844
|
+
* Message.frozen? => bool
|
852
845
|
*
|
853
|
-
*
|
854
|
-
* Ruby object
|
846
|
+
* Returns true if the message is frozen in either Ruby or the underlying
|
847
|
+
* representation. Freezes the Ruby message object if it is not already frozen
|
848
|
+
* in Ruby but it is frozen in the underlying representation.
|
855
849
|
*/
|
856
|
-
|
850
|
+
VALUE Message_frozen(VALUE _self) {
|
857
851
|
Message* self = ruby_to_Message(_self);
|
858
|
-
if (!
|
859
|
-
|
860
|
-
|
852
|
+
if (!upb_Message_IsFrozen(self->msg)) {
|
853
|
+
PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
|
854
|
+
return Qfalse;
|
861
855
|
}
|
862
|
-
|
856
|
+
|
857
|
+
// Lazily freeze the Ruby wrapper.
|
858
|
+
if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
|
859
|
+
return Qtrue;
|
863
860
|
}
|
864
861
|
|
865
862
|
/*
|
866
|
-
*
|
867
|
-
*
|
863
|
+
* call-seq:
|
864
|
+
* Message.freeze => self
|
865
|
+
*
|
866
|
+
* Freezes the message object. We have to intercept this so we can freeze the
|
867
|
+
* underlying representation, not just the Ruby wrapper.
|
868
868
|
*/
|
869
|
-
VALUE
|
869
|
+
VALUE Message_freeze(VALUE _self) {
|
870
870
|
Message* self = ruby_to_Message(_self);
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
for (int i = 0; i < n; i++) {
|
875
|
-
const upb_FieldDef* f = upb_MessageDef_Field(self->msgdef, i);
|
876
|
-
VALUE field = Message_getfield(_self, f);
|
877
|
-
|
878
|
-
if (field != Qnil) {
|
879
|
-
if (upb_FieldDef_IsMap(f)) {
|
880
|
-
Map_internal_deep_freeze(field);
|
881
|
-
} else if (upb_FieldDef_IsRepeated(f)) {
|
882
|
-
RepeatedField_internal_deep_freeze(field);
|
883
|
-
} else if (upb_FieldDef_IsSubMessage(f)) {
|
884
|
-
Message_internal_deep_freeze(field);
|
885
|
-
}
|
886
|
-
}
|
871
|
+
if (RB_OBJ_FROZEN(_self)) {
|
872
|
+
PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg));
|
873
|
+
return _self;
|
887
874
|
}
|
875
|
+
if (!upb_Message_IsFrozen(self->msg)) {
|
876
|
+
upb_Message_Freeze(Message_GetMutable(_self, NULL),
|
877
|
+
upb_MessageDef_MiniTable(self->msgdef));
|
878
|
+
}
|
879
|
+
RB_OBJ_FREEZE(_self);
|
888
880
|
return _self;
|
889
881
|
}
|
890
882
|
|
@@ -990,7 +982,7 @@ VALUE Message_decode_bytes(int size, const char* bytes, int options,
|
|
990
982
|
rb_raise(cParseError, "Error occurred during parsing");
|
991
983
|
}
|
992
984
|
if (freeze) {
|
993
|
-
|
985
|
+
Message_freeze(msg_rb);
|
994
986
|
}
|
995
987
|
return msg_rb;
|
996
988
|
}
|
@@ -1012,9 +1004,6 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1012
1004
|
int options = 0;
|
1013
1005
|
upb_Status status;
|
1014
1006
|
|
1015
|
-
// TODO: use this message's pool instead.
|
1016
|
-
const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
|
1017
|
-
|
1018
1007
|
if (argc < 1 || argc > 2) {
|
1019
1008
|
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
1020
1009
|
}
|
@@ -1048,8 +1037,9 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1048
1037
|
}
|
1049
1038
|
|
1050
1039
|
upb_Status_Clear(&status);
|
1040
|
+
const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
|
1051
1041
|
if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
|
1052
|
-
(upb_Message*)msg->msg, msg->msgdef,
|
1042
|
+
(upb_Message*)msg->msg, msg->msgdef, pool, options,
|
1053
1043
|
Arena_get(msg->arena), &status)) {
|
1054
1044
|
rb_raise(cParseError, "Error occurred during parsing: %s",
|
1055
1045
|
upb_Status_ErrorMessage(&status));
|
@@ -1128,9 +1118,6 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1128
1118
|
size_t size;
|
1129
1119
|
upb_Status status;
|
1130
1120
|
|
1131
|
-
// TODO: use this message's pool instead.
|
1132
|
-
const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
|
1133
|
-
|
1134
1121
|
if (argc < 1 || argc > 2) {
|
1135
1122
|
rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
|
1136
1123
|
}
|
@@ -1165,8 +1152,9 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1165
1152
|
}
|
1166
1153
|
|
1167
1154
|
upb_Status_Clear(&status);
|
1168
|
-
|
1169
|
-
|
1155
|
+
const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef));
|
1156
|
+
size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf),
|
1157
|
+
&status);
|
1170
1158
|
|
1171
1159
|
if (!upb_Status_IsOk(&status)) {
|
1172
1160
|
rb_raise(cParseError, "Error occurred during encoding: %s",
|
@@ -1176,7 +1164,7 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
|
|
1176
1164
|
VALUE ret;
|
1177
1165
|
if (size >= sizeof(buf)) {
|
1178
1166
|
char* buf2 = malloc(size + 1);
|
1179
|
-
upb_JsonEncode(msg->msg, msg->msgdef,
|
1167
|
+
upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1,
|
1180
1168
|
&status);
|
1181
1169
|
ret = rb_str_new(buf2, size);
|
1182
1170
|
free(buf2);
|
@@ -1402,6 +1390,7 @@ static void Message_define_class(VALUE klass) {
|
|
1402
1390
|
rb_define_method(klass, "==", Message_eq, 1);
|
1403
1391
|
rb_define_method(klass, "eql?", Message_eq, 1);
|
1404
1392
|
rb_define_method(klass, "freeze", Message_freeze, 0);
|
1393
|
+
rb_define_method(klass, "frozen?", Message_frozen, 0);
|
1405
1394
|
rb_define_method(klass, "hash", Message_hash, 0);
|
1406
1395
|
rb_define_method(klass, "to_h", Message_to_h, 0);
|
1407
1396
|
rb_define_method(klass, "inspect", Message_inspect, 0);
|
@@ -36,7 +36,7 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
|
|
36
36
|
|
37
37
|
// Gets or constructs a Ruby wrapper object for the given message. The wrapper
|
38
38
|
// object will reference |arena| and ensure that it outlives this object.
|
39
|
-
VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
|
39
|
+
VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m,
|
40
40
|
VALUE arena);
|
41
41
|
|
42
42
|
// Gets the given field from this message.
|
@@ -54,10 +54,6 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
|
|
54
54
|
upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
|
55
55
|
upb_Arena* arena);
|
56
56
|
|
57
|
-
// Returns true if these two messages are equal.
|
58
|
-
bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
|
59
|
-
const upb_MessageDef* m);
|
60
|
-
|
61
57
|
// Checks that this Ruby object is a message, and raises an exception if not.
|
62
58
|
void Message_CheckClass(VALUE klass);
|
63
59
|
|
@@ -78,7 +74,7 @@ VALUE Message_decode_bytes(int size, const char* bytes, int options,
|
|
78
74
|
VALUE klass, bool freeze);
|
79
75
|
|
80
76
|
// Recursively freeze message
|
81
|
-
VALUE
|
77
|
+
VALUE Message_freeze(VALUE _self);
|
82
78
|
|
83
79
|
// Call at startup to register all types in this module.
|
84
80
|
void Message_register(VALUE protobuf);
|
@@ -164,11 +164,23 @@ static void Arena_free(void *data) {
|
|
164
164
|
xfree(arena);
|
165
165
|
}
|
166
166
|
|
167
|
+
static size_t Arena_memsize(const void *data) {
|
168
|
+
const Arena *arena = data;
|
169
|
+
size_t fused_count;
|
170
|
+
size_t memsize = upb_Arena_SpaceAllocated(arena->arena, &fused_count);
|
171
|
+
if (fused_count > 1) {
|
172
|
+
// If other arena were fused we attribute an equal
|
173
|
+
// share of memory usage to each one.
|
174
|
+
memsize /= fused_count;
|
175
|
+
}
|
176
|
+
return memsize + sizeof(Arena);
|
177
|
+
}
|
178
|
+
|
167
179
|
static VALUE cArena;
|
168
180
|
|
169
181
|
const rb_data_type_t Arena_type = {
|
170
182
|
"Google::Protobuf::Internal::Arena",
|
171
|
-
{Arena_mark, Arena_free,
|
183
|
+
{Arena_mark, Arena_free, Arena_memsize},
|
172
184
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
173
185
|
};
|
174
186
|
|
@@ -209,15 +221,6 @@ void Arena_fuse(VALUE _arena, upb_Arena *other) {
|
|
209
221
|
|
210
222
|
VALUE Arena_new() { return Arena_alloc(cArena); }
|
211
223
|
|
212
|
-
void Arena_Pin(VALUE _arena, VALUE obj) {
|
213
|
-
Arena *arena;
|
214
|
-
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
|
215
|
-
if (arena->pinned_objs == Qnil) {
|
216
|
-
RB_OBJ_WRITE(_arena, &arena->pinned_objs, rb_ary_new());
|
217
|
-
}
|
218
|
-
rb_ary_push(arena->pinned_objs, obj);
|
219
|
-
}
|
220
|
-
|
221
224
|
void Arena_register(VALUE module) {
|
222
225
|
VALUE internal = rb_define_module_under(module, "Internal");
|
223
226
|
VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject);
|
@@ -241,16 +244,17 @@ static void ObjectCache_Init(VALUE protobuf) {
|
|
241
244
|
item_try_add = rb_intern("try_add");
|
242
245
|
|
243
246
|
rb_gc_register_address(&weak_obj_cache);
|
247
|
+
VALUE internal = rb_const_get(protobuf, rb_intern("Internal"));
|
244
248
|
#if SIZEOF_LONG >= SIZEOF_VALUE
|
245
|
-
VALUE cache_class = rb_const_get(
|
249
|
+
VALUE cache_class = rb_const_get(internal, rb_intern("ObjectCache"));
|
246
250
|
#else
|
247
|
-
VALUE cache_class = rb_const_get(
|
251
|
+
VALUE cache_class = rb_const_get(internal, rb_intern("LegacyObjectCache"));
|
248
252
|
#endif
|
249
253
|
|
250
254
|
weak_obj_cache = rb_class_new_instance(0, NULL, cache_class);
|
251
|
-
rb_const_set(
|
252
|
-
rb_const_set(
|
253
|
-
rb_const_set(
|
255
|
+
rb_const_set(internal, rb_intern("OBJECT_CACHE"), weak_obj_cache);
|
256
|
+
rb_const_set(internal, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG));
|
257
|
+
rb_const_set(internal, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE));
|
254
258
|
}
|
255
259
|
|
256
260
|
static VALUE ObjectCache_GetKey(const void *key) {
|
@@ -341,3 +345,14 @@ __attribute__((visibility("default"))) void Init_protobuf_c() {
|
|
341
345
|
rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
|
342
346
|
1);
|
343
347
|
}
|
348
|
+
|
349
|
+
// -----------------------------------------------------------------------------
|
350
|
+
// Utilities
|
351
|
+
// -----------------------------------------------------------------------------
|
352
|
+
|
353
|
+
// Raises a Ruby error if val is frozen in Ruby or UPB.
|
354
|
+
void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen) {
|
355
|
+
if (RB_UNLIKELY(rb_obj_frozen_p(val)||upb_frozen)) {
|
356
|
+
rb_error_frozen_object(val);
|
357
|
+
}
|
358
|
+
}
|