google-protobuf 4.27.2 → 4.35.1
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 +32 -14
- data/ext/google/protobuf_c/defs.c +475 -133
- data/ext/google/protobuf_c/extconf.rb +20 -10
- data/ext/google/protobuf_c/glue.c +63 -0
- data/ext/google/protobuf_c/map.c +145 -56
- data/ext/google/protobuf_c/map.h +6 -2
- data/ext/google/protobuf_c/message.c +180 -97
- data/ext/google/protobuf_c/message.h +2 -2
- data/ext/google/protobuf_c/protobuf.c +14 -13
- data/ext/google/protobuf_c/protobuf.h +3 -15
- data/ext/google/protobuf_c/repeated_field.c +134 -53
- data/ext/google/protobuf_c/repeated_field.h +5 -1
- data/ext/google/protobuf_c/ruby-upb.c +14522 -12698
- data/ext/google/protobuf_c/ruby-upb.h +8273 -4619
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +22 -282
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +2 -1
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
- data/lib/google/protobuf/any_pb.rb +1 -1
- data/lib/google/protobuf/api_pb.rb +2 -2
- data/lib/google/protobuf/descriptor_pb.rb +6 -2
- data/lib/google/protobuf/duration_pb.rb +1 -1
- data/lib/google/protobuf/empty_pb.rb +1 -1
- data/lib/google/protobuf/ffi/descriptor.rb +11 -2
- data/lib/google/protobuf/ffi/descriptor_pool.rb +7 -1
- data/lib/google/protobuf/ffi/enum_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/ffi.rb +5 -2
- data/lib/google/protobuf/ffi/field_descriptor.rb +16 -0
- data/lib/google/protobuf/ffi/file_descriptor.rb +36 -0
- data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
- data/lib/google/protobuf/ffi/internal/convert.rb +9 -6
- data/lib/google/protobuf/ffi/internal/pointer_helper.rb +2 -1
- data/lib/google/protobuf/ffi/map.rb +47 -23
- data/lib/google/protobuf/ffi/message.rb +188 -64
- data/lib/google/protobuf/ffi/method_descriptor.rb +11 -1
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/repeated_field.rb +42 -16
- data/lib/google/protobuf/ffi/service_descriptor.rb +11 -1
- data/lib/google/protobuf/field_mask_pb.rb +1 -1
- data/lib/google/protobuf/message_exts.rb +4 -0
- data/lib/google/protobuf/plugin_pb.rb +1 -1
- data/lib/google/protobuf/source_context_pb.rb +1 -1
- data/lib/google/protobuf/struct_pb.rb +1 -1
- data/lib/google/protobuf/timestamp_pb.rb +1 -1
- data/lib/google/protobuf/type_pb.rb +1 -1
- data/lib/google/protobuf/wrappers_pb.rb +1 -1
- data/lib/google/protobuf_ffi.rb +3 -2
- data/lib/google/tasks/ffi.rake +1 -1
- metadata +29 -34
- data/ext/google/protobuf_c/wrap_memcpy.c +0 -29
|
@@ -12,11 +12,38 @@ module Google
|
|
|
12
12
|
attach_function :file_def_name, :upb_FileDef_Name, [:FileDef], :string
|
|
13
13
|
attach_function :file_def_pool, :upb_FileDef_Pool, [:FileDef], :DefPool
|
|
14
14
|
attach_function :file_options, :FileDescriptor_serialized_options, [:FileDef, :pointer, Internal::Arena], :pointer
|
|
15
|
+
attach_function :file_to_proto, :FileDescriptor_serialized_to_proto, [:FileDef, :pointer, Internal::Arena], :pointer
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
class FileDescriptor
|
|
18
19
|
attr :descriptor_pool, :file_def
|
|
19
20
|
|
|
21
|
+
# FFI Interface methods and setup
|
|
22
|
+
extend ::FFI::DataConverter
|
|
23
|
+
native_type ::FFI::Type::POINTER
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
prepend Google::Protobuf::Internal::TypeSafety
|
|
27
|
+
include Google::Protobuf::Internal::PointerHelper
|
|
28
|
+
|
|
29
|
+
# @param value [FileDescriptor] FileDescriptor to convert to an FFI native type
|
|
30
|
+
# @param _ [Object] Unused
|
|
31
|
+
def to_native(value, _)
|
|
32
|
+
file_def_ptr = value.nil? ? nil : value.instance_variable_get(:@file_def)
|
|
33
|
+
return ::FFI::Pointer::NULL if file_def_ptr.nil?
|
|
34
|
+
raise "Underlying file_def was null!" if file_def_ptr.null?
|
|
35
|
+
file_def_ptr
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# @param file_def [::FFI::Pointer] FileDef pointer to be wrapped
|
|
40
|
+
# @param _ [Object] Unused
|
|
41
|
+
def from_native(file_def, _ = nil)
|
|
42
|
+
return nil if file_def.nil? or file_def.null?
|
|
43
|
+
descriptor_from_file_def(file_def)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
20
47
|
def initialize(file_def, descriptor_pool)
|
|
21
48
|
@descriptor_pool = descriptor_pool
|
|
22
49
|
@file_def = file_def
|
|
@@ -44,6 +71,15 @@ module Google
|
|
|
44
71
|
opts.freeze
|
|
45
72
|
end
|
|
46
73
|
end
|
|
74
|
+
|
|
75
|
+
def to_proto
|
|
76
|
+
@to_proto ||= begin
|
|
77
|
+
size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
|
|
78
|
+
temporary_arena = Google::Protobuf::FFI.create_arena
|
|
79
|
+
buffer = Google::Protobuf::FFI.file_to_proto(@file_def, size_ptr, temporary_arena)
|
|
80
|
+
Google::Protobuf::FileDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
47
83
|
end
|
|
48
84
|
end
|
|
49
85
|
end
|
|
@@ -12,8 +12,6 @@ module Google
|
|
|
12
12
|
module Protobuf
|
|
13
13
|
module Internal
|
|
14
14
|
class Arena
|
|
15
|
-
attr :pinned_messages
|
|
16
|
-
|
|
17
15
|
# FFI Interface methods and setup
|
|
18
16
|
extend ::FFI::DataConverter
|
|
19
17
|
native_type ::FFI::Type::POINTER
|
|
@@ -46,10 +44,6 @@ module Google
|
|
|
46
44
|
raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks"
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
|
-
|
|
50
|
-
def pin(message)
|
|
51
|
-
pinned_messages.push message
|
|
52
|
-
end
|
|
53
47
|
end
|
|
54
48
|
end
|
|
55
49
|
|
|
@@ -33,11 +33,14 @@ module Google
|
|
|
33
33
|
return_value[:bool_val] = value
|
|
34
34
|
when :string
|
|
35
35
|
raise TypeError.new "Invalid argument for string field '#{name}' (given #{value.class})." unless value.is_a?(String) or value.is_a?(Symbol)
|
|
36
|
-
|
|
36
|
+
value = value.to_s if value.is_a?(Symbol)
|
|
37
|
+
if value.encoding == Encoding::UTF_8
|
|
38
|
+
unless value.valid_encoding?
|
|
39
|
+
raise Encoding::InvalidByteSequenceError.new "String is invalid UTF-8"
|
|
40
|
+
end
|
|
41
|
+
string_value = value
|
|
42
|
+
else
|
|
37
43
|
string_value = value.to_s.encode("UTF-8")
|
|
38
|
-
rescue Encoding::UndefinedConversionError
|
|
39
|
-
# TODO - why not include the field name here?
|
|
40
|
-
raise Encoding::UndefinedConversionError.new "String is invalid UTF-8"
|
|
41
44
|
end
|
|
42
45
|
return_value[:str_val][:size] = string_value.bytesize
|
|
43
46
|
return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize)
|
|
@@ -70,7 +73,7 @@ module Google
|
|
|
70
73
|
case wkt
|
|
71
74
|
when :Timestamp
|
|
72
75
|
raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Time
|
|
73
|
-
new_message = Google::Protobuf::FFI.new_message_from_def msg_or_enum_def, arena
|
|
76
|
+
new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena
|
|
74
77
|
sec = Google::Protobuf::FFI::MessageValue.new
|
|
75
78
|
sec[:int64_val] = value.tv_sec
|
|
76
79
|
sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1
|
|
@@ -82,7 +85,7 @@ module Google
|
|
|
82
85
|
return_value[:msg_val] = new_message
|
|
83
86
|
when :Duration
|
|
84
87
|
raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Numeric
|
|
85
|
-
new_message = Google::Protobuf::FFI.new_message_from_def msg_or_enum_def, arena
|
|
88
|
+
new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena
|
|
86
89
|
sec = Google::Protobuf::FFI::MessageValue.new
|
|
87
90
|
sec[:int64_val] = value
|
|
88
91
|
sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1
|
|
@@ -13,7 +13,8 @@ module Google
|
|
|
13
13
|
# the pool, and either retrieve the wrapper object for the given pointer
|
|
14
14
|
# or create one. Assumes that the caller is the wrapper class for the
|
|
15
15
|
# given pointer and that it implements `private_constructor`.
|
|
16
|
-
def descriptor_from_file_def(file_def, pointer)
|
|
16
|
+
def descriptor_from_file_def(file_def, pointer = nil)
|
|
17
|
+
pointer = file_def if pointer.nil?
|
|
17
18
|
raise RuntimeError.new "FileDef is nil" if file_def.nil?
|
|
18
19
|
raise RuntimeError.new "FileDef is null" if file_def.null?
|
|
19
20
|
pool_def = Google::Protobuf::FFI.file_def_pool file_def
|
|
@@ -9,18 +9,20 @@ module Google
|
|
|
9
9
|
module Protobuf
|
|
10
10
|
class FFI
|
|
11
11
|
# Map
|
|
12
|
-
attach_function :map_clear,
|
|
13
|
-
attach_function :map_delete,
|
|
14
|
-
attach_function :map_get,
|
|
15
|
-
attach_function :create_map,
|
|
16
|
-
attach_function :map_size,
|
|
17
|
-
attach_function :map_set,
|
|
12
|
+
attach_function :map_clear, :upb_Map_Clear, [:Map], :void
|
|
13
|
+
attach_function :map_delete, :upb_Map_Delete, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool
|
|
14
|
+
attach_function :map_get, :upb_Map_Get, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool
|
|
15
|
+
attach_function :create_map, :upb_Map_New, [Internal::Arena, CType, CType], :Map
|
|
16
|
+
attach_function :map_size, :upb_Map_Size, [:Map], :size_t
|
|
17
|
+
attach_function :map_set, :upb_Map_Set, [:Map, MessageValue.by_value, MessageValue.by_value, Internal::Arena], :bool
|
|
18
|
+
attach_function :map_freeze, :upb_Map_Freeze, [:Map, MiniTable.by_ref], :void
|
|
19
|
+
attach_function :map_frozen?, :upb_Map_IsFrozen, [:Map], :bool
|
|
18
20
|
|
|
19
21
|
# MapIterator
|
|
20
|
-
attach_function :map_next,
|
|
21
|
-
attach_function :map_done,
|
|
22
|
-
attach_function :map_key,
|
|
23
|
-
attach_function :map_value,
|
|
22
|
+
attach_function :map_next, :upb_MapIterator_Next, [:Map, :pointer], :bool
|
|
23
|
+
attach_function :map_done, :upb_MapIterator_Done, [:Map, :size_t], :bool
|
|
24
|
+
attach_function :map_key, :upb_MapIterator_Key, [:Map, :size_t], MessageValue.by_value
|
|
25
|
+
attach_function :map_value, :upb_MapIterator_Value, [:Map, :size_t], MessageValue.by_value
|
|
24
26
|
end
|
|
25
27
|
class Map
|
|
26
28
|
include Enumerable
|
|
@@ -155,17 +157,35 @@ module Google
|
|
|
155
157
|
end
|
|
156
158
|
alias size length
|
|
157
159
|
|
|
160
|
+
##
|
|
161
|
+
# Is this object frozen?
|
|
162
|
+
# Returns true if either this Ruby wrapper or the underlying
|
|
163
|
+
# representation are frozen. Freezes the wrapper if the underlying
|
|
164
|
+
# representation is already frozen but this wrapper isn't.
|
|
165
|
+
def frozen?
|
|
166
|
+
unless Google::Protobuf::FFI.map_frozen? @map_ptr
|
|
167
|
+
raise RuntimeError.new "Ruby frozen Map with mutable representation" if super
|
|
168
|
+
return false
|
|
169
|
+
end
|
|
170
|
+
method(:freeze).super_method.call unless super
|
|
171
|
+
true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
##
|
|
175
|
+
# Freezes the map object. We have to intercept this so we can freeze the
|
|
176
|
+
# underlying representation, not just the Ruby wrapper. Returns self.
|
|
158
177
|
def freeze
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if value_type == :message
|
|
163
|
-
internal_iterator do |iterator|
|
|
164
|
-
value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator)
|
|
165
|
-
convert_upb_to_ruby(value_message_value, value_type, descriptor, arena).freeze
|
|
178
|
+
if method(:frozen?).super_method.call
|
|
179
|
+
unless Google::Protobuf::FFI.map_frozen? @map_ptr
|
|
180
|
+
raise RuntimeError.new "Underlying representation of map still mutable despite frozen wrapper"
|
|
166
181
|
end
|
|
182
|
+
return self
|
|
167
183
|
end
|
|
168
|
-
|
|
184
|
+
unless Google::Protobuf::FFI.map_frozen? @map_ptr
|
|
185
|
+
mini_table = (value_type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil
|
|
186
|
+
Google::Protobuf::FFI.map_freeze(@map_ptr, mini_table)
|
|
187
|
+
end
|
|
188
|
+
super
|
|
169
189
|
end
|
|
170
190
|
|
|
171
191
|
##
|
|
@@ -212,8 +232,8 @@ module Google
|
|
|
212
232
|
def hash
|
|
213
233
|
return_value = 0
|
|
214
234
|
each_msg_val do |key_message_value, value_message_value|
|
|
215
|
-
return_value
|
|
216
|
-
return_value
|
|
235
|
+
return_value += Google::Protobuf::FFI.message_value_hash(key_message_value, key_type, nil, 0)
|
|
236
|
+
return_value += Google::Protobuf::FFI.message_value_hash(value_message_value, value_type, descriptor, 0)
|
|
217
237
|
end
|
|
218
238
|
return_value
|
|
219
239
|
end
|
|
@@ -371,10 +391,14 @@ module Google
|
|
|
371
391
|
OBJECT_CACHE.try_add(@map_ptr.address, self)
|
|
372
392
|
end
|
|
373
393
|
|
|
374
|
-
|
|
375
|
-
#
|
|
394
|
+
##
|
|
395
|
+
# Constructor that uses the type information from the given
|
|
396
|
+
# FieldDescriptor to configure the new Map instance.
|
|
397
|
+
# @param field [FieldDescriptor] Type information for the new Map
|
|
376
398
|
# @param arena [Arena] Owning message's arena
|
|
377
|
-
|
|
399
|
+
# @param value [Hash|Map] Initial value
|
|
400
|
+
# @param map [::FFI::Pointer] Existing upb_Map
|
|
401
|
+
def self.construct_for_field(field, arena: nil, value: nil, map: nil)
|
|
378
402
|
raise ArgumentError.new "Expected Hash object as initializer value for map field '#{field.name}' (given #{value.class})." unless value.nil? or value.is_a? Hash
|
|
379
403
|
instance = allocate
|
|
380
404
|
raise ArgumentError.new "Expected field with type :message, instead got #{field.class}" unless field.type == :message
|
|
@@ -17,13 +17,16 @@ module Google
|
|
|
17
17
|
attach_function :get_message_has, :upb_Message_HasFieldByDef, [:Message, FieldDescriptor], :bool
|
|
18
18
|
attach_function :set_message_field, :upb_Message_SetFieldByDef, [:Message, FieldDescriptor, MessageValue.by_value, Internal::Arena], :bool
|
|
19
19
|
attach_function :encode_message, :upb_Encode, [:Message, MiniTable.by_ref, :size_t, Internal::Arena, :pointer, :pointer], EncodeStatus
|
|
20
|
-
attach_function :
|
|
20
|
+
attach_function :json_decode_message_detecting_nonconformance, :upb_JsonDecodeDetectingNonconformance, [:binary_string, :size_t, :Message, Descriptor, :DefPool, :int, Internal::Arena, Status.by_ref], :int
|
|
21
21
|
attach_function :json_encode_message, :upb_JsonEncode, [:Message, Descriptor, :DefPool, :int, :binary_string, :size_t, Status.by_ref], :size_t
|
|
22
22
|
attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus
|
|
23
23
|
attach_function :get_mutable_message, :upb_Message_Mutable, [:Message, FieldDescriptor, Internal::Arena], MutableMessageValue.by_value
|
|
24
|
-
attach_function :get_message_which_oneof, :
|
|
25
|
-
attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :int], :bool
|
|
24
|
+
attach_function :get_message_which_oneof, :upb_Message_WhichOneofByDef, [:Message, OneofDescriptor], FieldDescriptor
|
|
25
|
+
attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :DefPool, :int], :bool
|
|
26
26
|
attach_function :message_next, :upb_Message_Next, [:Message, Descriptor, :DefPool, :FieldDefPointer, MessageValue.by_ref, :pointer], :bool
|
|
27
|
+
attach_function :message_freeze, :upb_Message_Freeze, [:Message, MiniTable.by_ref], :void
|
|
28
|
+
attach_function :message_frozen?, :upb_Message_IsFrozen, [:Message], :bool
|
|
29
|
+
|
|
27
30
|
# MessageValue
|
|
28
31
|
attach_function :message_value_equal, :shared_Msgval_IsEqual, [MessageValue.by_value, MessageValue.by_value, CType, Descriptor], :bool
|
|
29
32
|
attach_function :message_value_hash, :shared_Msgval_GetHash, [MessageValue.by_value, CType, Descriptor, :uint64_t], :uint64_t
|
|
@@ -58,18 +61,35 @@ module Google
|
|
|
58
61
|
instance
|
|
59
62
|
end
|
|
60
63
|
|
|
64
|
+
##
|
|
65
|
+
# Is this object frozen?
|
|
66
|
+
# Returns true if either this Ruby wrapper or the underlying
|
|
67
|
+
# representation are frozen. Freezes the wrapper if the underlying
|
|
68
|
+
# representation is already frozen but this wrapper isn't.
|
|
69
|
+
def frozen?
|
|
70
|
+
unless Google::Protobuf::FFI.message_frozen? @msg
|
|
71
|
+
raise RuntimeError.new "Ruby frozen Message with mutable representation" if super
|
|
72
|
+
return false
|
|
73
|
+
end
|
|
74
|
+
method(:freeze).super_method.call unless super
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Freezes the map object. We have to intercept this so we can freeze the
|
|
80
|
+
# underlying representation, not just the Ruby wrapper. Returns self.
|
|
61
81
|
def freeze
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.class.descriptor.each do |field_descriptor|
|
|
66
|
-
next if field_descriptor.has_presence? && !Google::Protobuf::FFI.get_message_has(@msg, field_descriptor)
|
|
67
|
-
if field_descriptor.map? or field_descriptor.repeated? or field_descriptor.sub_message?
|
|
68
|
-
get_field(field_descriptor).freeze
|
|
82
|
+
if method(:frozen?).super_method.call
|
|
83
|
+
unless Google::Protobuf::FFI.message_frozen? @msg
|
|
84
|
+
raise RuntimeError.new "Underlying representation of message still mutable despite frozen wrapper"
|
|
69
85
|
end
|
|
86
|
+
return self
|
|
70
87
|
end
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
unless Google::Protobuf::FFI.message_frozen? @msg
|
|
89
|
+
Google::Protobuf::FFI.message_freeze(@msg, Google::Protobuf::FFI.get_mini_table(self.class.descriptor))
|
|
90
|
+
end
|
|
91
|
+
super
|
|
92
|
+
end
|
|
73
93
|
|
|
74
94
|
def dup
|
|
75
95
|
duplicate = self.class.private_constructor(@arena)
|
|
@@ -234,7 +254,7 @@ module Google
|
|
|
234
254
|
decoding_options = 0
|
|
235
255
|
unless options.is_a? Hash
|
|
236
256
|
if options.respond_to? :to_h
|
|
237
|
-
options options.to_h
|
|
257
|
+
options = options.to_h
|
|
238
258
|
else
|
|
239
259
|
#TODO can this error message be improve to include what was received?
|
|
240
260
|
raise ArgumentError.new "Expected hash arguments"
|
|
@@ -250,7 +270,9 @@ module Google
|
|
|
250
270
|
message = new
|
|
251
271
|
pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool
|
|
252
272
|
status = Google::Protobuf::FFI::Status.new
|
|
253
|
-
|
|
273
|
+
result = Google::Protobuf::FFI.json_decode_message_detecting_nonconformance(data, data.bytesize, message.instance_variable_get(:@msg), message.class.descriptor, pool_def, decoding_options, message.instance_variable_get(:@arena), status)
|
|
274
|
+
case result
|
|
275
|
+
when Google::Protobuf::FFI::Upb_JsonDecodeResult_Error
|
|
254
276
|
raise ParseError.new "Error occurred during parsing: #{Google::Protobuf::FFI.error_message(status)}"
|
|
255
277
|
end
|
|
256
278
|
message
|
|
@@ -309,42 +331,136 @@ module Google
|
|
|
309
331
|
|
|
310
332
|
include Google::Protobuf::Internal::Convert
|
|
311
333
|
|
|
334
|
+
##
|
|
335
|
+
# Checks ObjectCache for a sentinel empty frozen Map of the key and
|
|
336
|
+
# value types matching the field descriptor's MessageDef and returns
|
|
337
|
+
# the cache entry. If an entry is not found, one is created and added
|
|
338
|
+
# to the cache keyed by the MessageDef pointer first.
|
|
339
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
340
|
+
def empty_frozen_map(field_descriptor)
|
|
341
|
+
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
|
|
342
|
+
frozen_map = OBJECT_CACHE.get sub_message_def
|
|
343
|
+
if frozen_map.nil?
|
|
344
|
+
frozen_map = Google::Protobuf::Map.send(:construct_for_field, field_descriptor)
|
|
345
|
+
OBJECT_CACHE.try_add(sub_message_def, frozen_map.freeze)
|
|
346
|
+
end
|
|
347
|
+
raise "Empty Frozen Map is not frozen" unless frozen_map.frozen?
|
|
348
|
+
frozen_map
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
##
|
|
352
|
+
# Returns a frozen Map instance for the given field. If the message
|
|
353
|
+
# already has a value for that field, it is used. If not, a sentinel
|
|
354
|
+
# (per FieldDescriptor) empty frozen Map is returned instead.
|
|
355
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
356
|
+
def frozen_map_from_field_descriptor(field_descriptor)
|
|
357
|
+
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
358
|
+
return empty_frozen_map field_descriptor if message_value[:map_val].null?
|
|
359
|
+
get_map_field(message_value[:map_val], field_descriptor).freeze
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
##
|
|
363
|
+
# Returns a Map instance for the given field. If the message is frozen
|
|
364
|
+
# the return value is also frozen. If not, a mutable instance is
|
|
365
|
+
# returned instead.
|
|
366
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
367
|
+
def map_from_field_descriptor(field_descriptor)
|
|
368
|
+
return frozen_map_from_field_descriptor field_descriptor if frozen?
|
|
369
|
+
mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
|
|
370
|
+
get_map_field(mutable_message_value[:map], field_descriptor)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
##
|
|
374
|
+
# Checks ObjectCache for a sentinel empty frozen RepeatedField of the
|
|
375
|
+
# value type matching the field descriptor's MessageDef and returns
|
|
376
|
+
# the cache entry. If an entry is not found, one is created and added
|
|
377
|
+
# to the cache keyed by the MessageDef pointer first.
|
|
378
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
379
|
+
def empty_frozen_repeated_field(field_descriptor)
|
|
380
|
+
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
|
|
381
|
+
frozen_repeated_field = OBJECT_CACHE.get sub_message_def
|
|
382
|
+
if frozen_repeated_field.nil?
|
|
383
|
+
frozen_repeated_field = Google::Protobuf::RepeatedField.send(:construct_for_field, field_descriptor)
|
|
384
|
+
OBJECT_CACHE.try_add(sub_message_def, frozen_repeated_field.freeze)
|
|
385
|
+
end
|
|
386
|
+
raise "Empty frozen RepeatedField is not frozen" unless frozen_repeated_field.frozen?
|
|
387
|
+
frozen_repeated_field
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
##
|
|
391
|
+
# Returns a frozen RepeatedField instance for the given field. If the
|
|
392
|
+
# message already has a value for that field, it is used. If not, a
|
|
393
|
+
# sentinel (per FieldDescriptor) empty frozen RepeatedField is
|
|
394
|
+
# returned instead.
|
|
395
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
396
|
+
def frozen_repeated_field_from_field_descriptor(field_descriptor)
|
|
397
|
+
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
398
|
+
return empty_frozen_repeated_field field_descriptor if message_value[:array_val].null?
|
|
399
|
+
get_repeated_field(message_value[:array_val], field_descriptor).freeze
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
##
|
|
403
|
+
# Returns a RepeatedField instance for the given field. If the message
|
|
404
|
+
# is frozen the return value is also frozen. If not, a mutable
|
|
405
|
+
# instance is returned instead.
|
|
406
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
407
|
+
def repeated_field_from_field_descriptor(field_descriptor)
|
|
408
|
+
return frozen_repeated_field_from_field_descriptor field_descriptor if frozen?
|
|
409
|
+
mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
|
|
410
|
+
get_repeated_field(mutable_message_value[:array], field_descriptor)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
##
|
|
414
|
+
# Returns a Message instance for the given field. If the message
|
|
415
|
+
# is frozen nil is always returned. Otherwise, a mutable instance is
|
|
416
|
+
# returned instead.
|
|
417
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
418
|
+
def message_from_field_descriptor(field_descriptor)
|
|
419
|
+
return nil if frozen?
|
|
420
|
+
return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor
|
|
421
|
+
mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
|
|
422
|
+
sub_message = mutable_message[:msg]
|
|
423
|
+
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
|
|
424
|
+
Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
##
|
|
428
|
+
# Returns a scalar value for the given field. If the message
|
|
429
|
+
# is frozen the return value is also frozen.
|
|
430
|
+
# @param field_descriptor [FieldDescriptor] Field to retrieve.
|
|
431
|
+
def scalar_from_field_descriptor(field_descriptor)
|
|
432
|
+
c_type = field_descriptor.send(:c_type)
|
|
433
|
+
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
434
|
+
msg_or_enum_def = c_type == :enum ? Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor) : nil
|
|
435
|
+
return_value = convert_upb_to_ruby message_value, c_type, msg_or_enum_def
|
|
436
|
+
frozen? ? return_value.freeze : return_value
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
##
|
|
440
|
+
# Dynamically define accessors methods for every field of @descriptor.
|
|
441
|
+
# Methods with names that conflict with existing methods are skipped.
|
|
312
442
|
def self.setup_accessors!
|
|
313
443
|
@descriptor.each do |field_descriptor|
|
|
314
444
|
field_name = field_descriptor.name
|
|
315
445
|
unless instance_methods(true).include?(field_name.to_sym)
|
|
316
|
-
#
|
|
317
|
-
#
|
|
446
|
+
# Dispatching to either index_internal or get_field is logically
|
|
447
|
+
# correct, but slightly slower due to having to perform extra
|
|
448
|
+
# lookups on each invocation rather than doing it once here.
|
|
318
449
|
if field_descriptor.map?
|
|
319
450
|
define_method(field_name) do
|
|
320
|
-
|
|
321
|
-
get_map_field(mutable_message_value[:map], field_descriptor)
|
|
451
|
+
map_from_field_descriptor field_descriptor
|
|
322
452
|
end
|
|
323
453
|
elsif field_descriptor.repeated?
|
|
324
454
|
define_method(field_name) do
|
|
325
|
-
|
|
326
|
-
get_repeated_field(mutable_message_value[:array], field_descriptor)
|
|
455
|
+
repeated_field_from_field_descriptor field_descriptor
|
|
327
456
|
end
|
|
328
457
|
elsif field_descriptor.sub_message?
|
|
329
458
|
define_method(field_name) do
|
|
330
|
-
|
|
331
|
-
mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
|
|
332
|
-
sub_message = mutable_message[:msg]
|
|
333
|
-
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field_descriptor)
|
|
334
|
-
Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
|
|
459
|
+
message_from_field_descriptor field_descriptor
|
|
335
460
|
end
|
|
336
461
|
else
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
define_method(field_name) do
|
|
340
|
-
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
341
|
-
convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor)
|
|
342
|
-
end
|
|
343
|
-
else
|
|
344
|
-
define_method(field_name) do
|
|
345
|
-
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
346
|
-
convert_upb_to_ruby message_value, c_type
|
|
347
|
-
end
|
|
462
|
+
define_method(field_name) do
|
|
463
|
+
scalar_from_field_descriptor field_descriptor
|
|
348
464
|
end
|
|
349
465
|
end
|
|
350
466
|
define_method("#{field_name}=") do |value|
|
|
@@ -354,14 +470,16 @@ module Google
|
|
|
354
470
|
clear_internal(field_descriptor)
|
|
355
471
|
end
|
|
356
472
|
if field_descriptor.type == :enum
|
|
357
|
-
|
|
358
|
-
|
|
473
|
+
if field_descriptor.repeated?
|
|
474
|
+
define_method("#{field_name}_const") do
|
|
359
475
|
return_value = []
|
|
360
|
-
|
|
476
|
+
repeated_field_from_field_descriptor(field_descriptor).send(:each_msg_val) do |msg_val|
|
|
361
477
|
return_value << msg_val[:int32_val]
|
|
362
478
|
end
|
|
363
479
|
return_value
|
|
364
|
-
|
|
480
|
+
end
|
|
481
|
+
else
|
|
482
|
+
define_method("#{field_name}_const") do
|
|
365
483
|
message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
|
|
366
484
|
message_value[:int32_val]
|
|
367
485
|
end
|
|
@@ -388,12 +506,21 @@ module Google
|
|
|
388
506
|
end
|
|
389
507
|
end
|
|
390
508
|
|
|
509
|
+
##
|
|
510
|
+
# Dynamically define accessors methods for every OneOf field of
|
|
511
|
+
# @descriptor.
|
|
391
512
|
def self.setup_oneof_accessors!
|
|
392
513
|
@oneof_field_names = []
|
|
393
514
|
@descriptor.each_oneof do |oneof_descriptor|
|
|
394
515
|
self.add_oneof_accessors_for! oneof_descriptor
|
|
395
516
|
end
|
|
396
517
|
end
|
|
518
|
+
|
|
519
|
+
##
|
|
520
|
+
# Dynamically define accessors methods for the given OneOf field.
|
|
521
|
+
# Methods with names that conflict with existing methods are skipped.
|
|
522
|
+
# @param oneof_descriptor [OneofDescriptor] Field to create accessors
|
|
523
|
+
# for.
|
|
397
524
|
def self.add_oneof_accessors_for!(oneof_descriptor)
|
|
398
525
|
field_name = oneof_descriptor.name.to_sym
|
|
399
526
|
@oneof_field_names << field_name
|
|
@@ -524,6 +651,10 @@ module Google
|
|
|
524
651
|
Google::Protobuf::FFI.clear_message_field(@msg, field_def)
|
|
525
652
|
end
|
|
526
653
|
|
|
654
|
+
# Accessor for field by name. Does not delegate to methods setup by
|
|
655
|
+
# self.setup_accessors! in order to avoid conflicts with bad field
|
|
656
|
+
# names e.g. `dup` or `class` which are perfectly valid for proto
|
|
657
|
+
# fields.
|
|
527
658
|
def index_internal(name)
|
|
528
659
|
field_descriptor = self.class.descriptor.lookup(name)
|
|
529
660
|
get_field field_descriptor unless field_descriptor.nil?
|
|
@@ -551,7 +682,7 @@ module Google
|
|
|
551
682
|
# one if omitted or nil.
|
|
552
683
|
def initialize(initial_value = nil, arena = nil, msg = nil)
|
|
553
684
|
@arena = arena || Google::Protobuf::FFI.create_arena
|
|
554
|
-
@msg = msg || Google::Protobuf::FFI.new_message_from_def(self.class.descriptor, @arena)
|
|
685
|
+
@msg = msg || Google::Protobuf::FFI.new_message_from_def(Google::Protobuf::FFI.get_mini_table(self.class.descriptor), @arena)
|
|
555
686
|
|
|
556
687
|
unless initial_value.nil?
|
|
557
688
|
raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each
|
|
@@ -572,9 +703,9 @@ module Google
|
|
|
572
703
|
|
|
573
704
|
next if value.nil?
|
|
574
705
|
if field_descriptor.map?
|
|
575
|
-
index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, @arena, value: value), name: key.to_s)
|
|
706
|
+
index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, arena: @arena, value: value), name: key.to_s)
|
|
576
707
|
elsif field_descriptor.repeated?
|
|
577
|
-
index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, @arena, values: value), name: key.to_s)
|
|
708
|
+
index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, arena: @arena, values: value), name: key.to_s)
|
|
578
709
|
else
|
|
579
710
|
index_assign_internal(value, name: key.to_s)
|
|
580
711
|
end
|
|
@@ -587,21 +718,20 @@ module Google
|
|
|
587
718
|
end
|
|
588
719
|
|
|
589
720
|
##
|
|
590
|
-
# Gets a field of this message identified by
|
|
721
|
+
# Gets a field of this message identified by FieldDescriptor.
|
|
591
722
|
#
|
|
592
|
-
# @param field [FieldDescriptor]
|
|
723
|
+
# @param field [FieldDescriptor] Field to retrieve.
|
|
724
|
+
# @param unwrap [Boolean](false) If true, unwraps wrappers.
|
|
593
725
|
def get_field(field, unwrap: false)
|
|
594
726
|
if field.map?
|
|
595
|
-
|
|
596
|
-
get_map_field(mutable_message_value[:map], field)
|
|
727
|
+
map_from_field_descriptor field
|
|
597
728
|
elsif field.repeated?
|
|
598
|
-
|
|
599
|
-
get_repeated_field(mutable_message_value[:array], field)
|
|
729
|
+
repeated_field_from_field_descriptor field
|
|
600
730
|
elsif field.sub_message?
|
|
601
731
|
return nil unless Google::Protobuf::FFI.get_message_has @msg, field
|
|
602
|
-
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field)
|
|
603
732
|
if unwrap
|
|
604
733
|
if field.has?(self)
|
|
734
|
+
sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field
|
|
605
735
|
wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field
|
|
606
736
|
fields = Google::Protobuf::FFI.field_count(sub_message_def)
|
|
607
737
|
raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1
|
|
@@ -612,42 +742,36 @@ module Google
|
|
|
612
742
|
nil
|
|
613
743
|
end
|
|
614
744
|
else
|
|
615
|
-
|
|
616
|
-
sub_message = mutable_message[:msg]
|
|
617
|
-
Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
|
|
745
|
+
message_from_field_descriptor field
|
|
618
746
|
end
|
|
619
747
|
else
|
|
620
|
-
|
|
621
|
-
message_value = Google::Protobuf::FFI.get_message_value @msg, field
|
|
622
|
-
if c_type == :enum
|
|
623
|
-
convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field)
|
|
624
|
-
else
|
|
625
|
-
convert_upb_to_ruby message_value, c_type
|
|
626
|
-
end
|
|
748
|
+
scalar_from_field_descriptor field
|
|
627
749
|
end
|
|
628
750
|
end
|
|
629
751
|
|
|
630
752
|
##
|
|
631
|
-
#
|
|
753
|
+
# Gets a RepeatedField from the ObjectCache or creates a new one.
|
|
754
|
+
# @param array [::FFI::Pointer] Pointer to the upb_Array
|
|
632
755
|
# @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field
|
|
633
756
|
def get_repeated_field(array, field)
|
|
634
757
|
return nil if array.nil? or array.null?
|
|
635
758
|
repeated_field = OBJECT_CACHE.get(array.address)
|
|
636
759
|
if repeated_field.nil?
|
|
637
|
-
repeated_field = RepeatedField.send(:construct_for_field, field, @arena, array: array)
|
|
760
|
+
repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array)
|
|
638
761
|
repeated_field.freeze if frozen?
|
|
639
762
|
end
|
|
640
763
|
repeated_field
|
|
641
764
|
end
|
|
642
765
|
|
|
643
766
|
##
|
|
644
|
-
#
|
|
767
|
+
# Gets a Map from the ObjectCache or creates a new one.
|
|
768
|
+
# @param map [::FFI::Pointer] Pointer to the upb_Map
|
|
645
769
|
# @param field [Google::Protobuf::FieldDescriptor] Type of the map field
|
|
646
770
|
def get_map_field(map, field)
|
|
647
771
|
return nil if map.nil? or map.null?
|
|
648
772
|
map_field = OBJECT_CACHE.get(map.address)
|
|
649
773
|
if map_field.nil?
|
|
650
|
-
map_field = Google::Protobuf::Map.send(:construct_for_field, field, @arena, map: map)
|
|
774
|
+
map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map)
|
|
651
775
|
map_field.freeze if frozen?
|
|
652
776
|
end
|
|
653
777
|
map_field
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
module Google
|
|
9
9
|
module Protobuf
|
|
10
|
-
class MethodDescriptor
|
|
10
|
+
class MethodDescriptor
|
|
11
11
|
attr :method_def, :descriptor_pool
|
|
12
12
|
|
|
13
13
|
include Google::Protobuf::Internal::Convert
|
|
@@ -81,6 +81,15 @@ module Google
|
|
|
81
81
|
@server_streaming ||= Google::Protobuf::FFI.method_server_streaming(self)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def to_proto
|
|
85
|
+
@to_proto ||= begin
|
|
86
|
+
size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
|
|
87
|
+
temporary_arena = Google::Protobuf::FFI.create_arena
|
|
88
|
+
buffer = Google::Protobuf::FFI.method_to_proto(self, size_ptr, temporary_arena)
|
|
89
|
+
Google::Protobuf::MethodDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
84
93
|
private
|
|
85
94
|
|
|
86
95
|
def initialize(method_def, descriptor_pool)
|
|
@@ -108,6 +117,7 @@ module Google
|
|
|
108
117
|
attach_function :method_output_type, :upb_MethodDef_OutputType, [MethodDescriptor], Descriptor
|
|
109
118
|
attach_function :method_client_streaming, :upb_MethodDef_ClientStreaming, [MethodDescriptor], :bool
|
|
110
119
|
attach_function :method_server_streaming, :upb_MethodDef_ServerStreaming, [MethodDescriptor], :bool
|
|
120
|
+
attach_function :method_to_proto, :MethodDescriptor_serialized_to_proto, [MethodDescriptor, :pointer, Internal::Arena], :pointer
|
|
111
121
|
end
|
|
112
122
|
end
|
|
113
123
|
end
|