google-protobuf 3.23.3 → 4.27.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.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +28 -72
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +512 -60
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +2 -1
  8. data/ext/google/protobuf_c/glue.c +72 -0
  9. data/ext/google/protobuf_c/map.c +28 -36
  10. data/ext/google/protobuf_c/map.h +6 -28
  11. data/ext/google/protobuf_c/message.c +88 -143
  12. data/ext/google/protobuf_c/message.h +10 -32
  13. data/ext/google/protobuf_c/protobuf.c +49 -175
  14. data/ext/google/protobuf_c/protobuf.h +24 -32
  15. data/ext/google/protobuf_c/repeated_field.c +23 -33
  16. data/ext/google/protobuf_c/repeated_field.h +6 -28
  17. data/ext/google/protobuf_c/ruby-upb.c +13046 -10690
  18. data/ext/google/protobuf_c/ruby-upb.h +8405 -5836
  19. data/ext/google/protobuf_c/shared_convert.c +69 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +37 -0
  22. data/ext/google/protobuf_c/shared_message.h +21 -0
  23. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
  24. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
  25. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  26. data/lib/google/protobuf/any_pb.rb +1 -22
  27. data/lib/google/protobuf/api_pb.rb +1 -24
  28. data/lib/google/protobuf/descriptor_pb.rb +14 -23
  29. data/lib/google/protobuf/duration_pb.rb +1 -22
  30. data/lib/google/protobuf/empty_pb.rb +1 -22
  31. data/lib/google/protobuf/ffi/descriptor.rb +166 -0
  32. data/lib/google/protobuf/ffi/descriptor_pool.rb +77 -0
  33. data/lib/google/protobuf/ffi/enum_descriptor.rb +173 -0
  34. data/lib/google/protobuf/ffi/ffi.rb +210 -0
  35. data/lib/google/protobuf/ffi/field_descriptor.rb +330 -0
  36. data/lib/google/protobuf/ffi/file_descriptor.rb +49 -0
  37. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  38. data/lib/google/protobuf/ffi/internal/convert.rb +289 -0
  39. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  40. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  41. data/lib/google/protobuf/ffi/map.rb +409 -0
  42. data/lib/google/protobuf/ffi/message.rb +659 -0
  43. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  44. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  45. data/lib/google/protobuf/ffi/oneof_descriptor.rb +97 -0
  46. data/lib/google/protobuf/ffi/repeated_field.rb +385 -0
  47. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  48. data/lib/google/protobuf/field_mask_pb.rb +1 -22
  49. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  50. data/lib/google/protobuf/message_exts.rb +3 -26
  51. data/lib/google/protobuf/plugin_pb.rb +2 -24
  52. data/lib/google/protobuf/repeated_field.rb +7 -31
  53. data/lib/google/protobuf/source_context_pb.rb +1 -22
  54. data/lib/google/protobuf/struct_pb.rb +1 -22
  55. data/lib/google/protobuf/timestamp_pb.rb +1 -22
  56. data/lib/google/protobuf/type_pb.rb +1 -24
  57. data/lib/google/protobuf/well_known_types.rb +5 -34
  58. data/lib/google/protobuf/wrappers_pb.rb +1 -22
  59. data/lib/google/protobuf.rb +27 -45
  60. data/lib/google/protobuf_ffi.rb +51 -0
  61. data/lib/google/protobuf_native.rb +19 -0
  62. data/lib/google/tasks/ffi.rake +100 -0
  63. metadata +89 -8
  64. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  65. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  66. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  67. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
@@ -0,0 +1,114 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2024 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ class MethodDescriptor
11
+ attr :method_def, :descriptor_pool
12
+
13
+ include Google::Protobuf::Internal::Convert
14
+
15
+ # FFI Interface methods and setup
16
+ extend ::FFI::DataConverter
17
+ native_type ::FFI::Type::POINTER
18
+
19
+ class << self
20
+ prepend Google::Protobuf::Internal::TypeSafety
21
+ include Google::Protobuf::Internal::PointerHelper
22
+
23
+ # @param value [MethodDescriptor] MethodDescriptor to convert to an FFI native type
24
+ # @param _ [Object] Unused
25
+ def to_native(value, _)
26
+ method_def_ptr = value.nil? ? nil : value.instance_variable_get(:@method_def)
27
+ return ::FFI::Pointer::NULL if method_def_ptr.nil?
28
+ raise "Underlying method_def was null!" if method_def_ptr.null?
29
+ method_def_ptr
30
+ end
31
+
32
+ ##
33
+ # @param service_def [::FFI::Pointer] MethodDef pointer to be wrapped
34
+ # @param _ [Object] Unused
35
+ def from_native(method_def, _ = nil)
36
+ return nil if method_def.nil? or method_def.null?
37
+ service_def = Google::Protobuf::FFI.raw_service_def_by_raw_method_def(method_def)
38
+ file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def)
39
+ descriptor_from_file_def(file_def, method_def)
40
+ end
41
+ end
42
+
43
+ def self.new(*arguments, &block)
44
+ raise "Descriptor objects may not be created from Ruby."
45
+ end
46
+
47
+ def to_s
48
+ inspect
49
+ end
50
+
51
+ def inspect
52
+ "#{self.class.name}: #{name}"
53
+ end
54
+
55
+ def name
56
+ @name ||= Google::Protobuf::FFI.get_method_name(self)
57
+ end
58
+
59
+ def options
60
+ @options ||= begin
61
+ size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
62
+ temporary_arena = Google::Protobuf::FFI.create_arena
63
+ buffer = Google::Protobuf::FFI.method_options(self, size_ptr, temporary_arena)
64
+ Google::Protobuf::MethodOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze
65
+ end
66
+ end
67
+
68
+ def input_type
69
+ @input_type ||= Google::Protobuf::FFI.method_input_type(self)
70
+ end
71
+
72
+ def output_type
73
+ @output_type ||= Google::Protobuf::FFI.method_output_type(self)
74
+ end
75
+
76
+ def client_streaming
77
+ @client_streaming ||= Google::Protobuf::FFI.method_client_streaming(self)
78
+ end
79
+
80
+ def server_streaming
81
+ @server_streaming ||= Google::Protobuf::FFI.method_server_streaming(self)
82
+ end
83
+
84
+ private
85
+
86
+ def initialize(method_def, descriptor_pool)
87
+ @method_def = method_def
88
+ @descriptor_pool = descriptor_pool
89
+ end
90
+
91
+ def self.private_constructor(method_def, descriptor_pool)
92
+ instance = allocate
93
+ instance.send(:initialize, method_def, descriptor_pool)
94
+ instance
95
+ end
96
+
97
+ def c_type
98
+ @c_type ||= Google::Protobuf::FFI.get_c_type(self)
99
+ end
100
+ end
101
+
102
+ class FFI
103
+ # MethodDef
104
+ attach_function :raw_service_def_by_raw_method_def, :upb_MethodDef_Service, [:pointer], :pointer
105
+ attach_function :get_method_name, :upb_MethodDef_Name, [MethodDescriptor], :string
106
+ attach_function :method_options, :MethodDescriptor_serialized_options, [MethodDescriptor, :pointer, Internal::Arena], :pointer
107
+ attach_function :method_input_type, :upb_MethodDef_InputType, [MethodDescriptor], Descriptor
108
+ attach_function :method_output_type, :upb_MethodDef_OutputType, [MethodDescriptor], Descriptor
109
+ attach_function :method_client_streaming, :upb_MethodDef_ClientStreaming, [MethodDescriptor], :bool
110
+ attach_function :method_server_streaming, :upb_MethodDef_ServerStreaming, [MethodDescriptor], :bool
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,30 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2022 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ private
11
+
12
+ SIZEOF_LONG = ::FFI::MemoryPointer.new(:long).size
13
+ SIZEOF_VALUE = ::FFI::Pointer::SIZE
14
+
15
+ def self.interpreter_supports_non_finalized_keys_in_weak_map?
16
+ ! defined? JRUBY_VERSION
17
+ end
18
+
19
+ def self.cache_implementation
20
+ if interpreter_supports_non_finalized_keys_in_weak_map? and SIZEOF_LONG >= SIZEOF_VALUE
21
+ Google::Protobuf::Internal::ObjectCache
22
+ else
23
+ Google::Protobuf::Internal::LegacyObjectCache
24
+ end
25
+ end
26
+
27
+ public
28
+ OBJECT_CACHE = cache_implementation.new
29
+ end
30
+ end
@@ -0,0 +1,97 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2022 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ class OneofDescriptor
11
+ attr :descriptor_pool, :oneof_def
12
+ include Enumerable
13
+
14
+ # FFI Interface methods and setup
15
+ extend ::FFI::DataConverter
16
+ native_type ::FFI::Type::POINTER
17
+
18
+ class << self
19
+ prepend Google::Protobuf::Internal::TypeSafety
20
+ include Google::Protobuf::Internal::PointerHelper
21
+
22
+ # @param value [OneofDescriptor] FieldDescriptor to convert to an FFI native type
23
+ # @param _ [Object] Unused
24
+ def to_native(value, _ = nil)
25
+ value.instance_variable_get(:@oneof_def) || ::FFI::Pointer::NULL
26
+ end
27
+
28
+ ##
29
+ # @param oneof_def [::FFI::Pointer] OneofDef pointer to be wrapped
30
+ # @param _ [Object] Unused
31
+ def from_native(oneof_def, _ = nil)
32
+ return nil if oneof_def.nil? or oneof_def.null?
33
+ message_descriptor = Google::Protobuf::FFI.get_oneof_containing_type oneof_def
34
+ raise RuntimeError.new "Message Descriptor is nil" if message_descriptor.nil?
35
+ file_def = Google::Protobuf::FFI.get_message_file_def message_descriptor.to_native
36
+ descriptor_from_file_def(file_def, oneof_def)
37
+ end
38
+ end
39
+
40
+ def self.new(*arguments, &block)
41
+ raise "OneofDescriptor objects may not be created from Ruby."
42
+ end
43
+
44
+ def name
45
+ Google::Protobuf::FFI.get_oneof_name(self)
46
+ end
47
+
48
+ def each &block
49
+ n = Google::Protobuf::FFI.get_oneof_field_count(self)
50
+ 0.upto(n-1) do |i|
51
+ yield(Google::Protobuf::FFI.get_oneof_field_by_index(self, i))
52
+ end
53
+ nil
54
+ end
55
+
56
+ def options
57
+ @options ||= begin
58
+ size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
59
+ temporary_arena = Google::Protobuf::FFI.create_arena
60
+ buffer = Google::Protobuf::FFI.oneof_options(self, size_ptr, temporary_arena)
61
+ opts = Google::Protobuf::OneofOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze)
62
+ opts.clear_features()
63
+ opts.freeze
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def initialize(oneof_def, descriptor_pool)
70
+ @descriptor_pool = descriptor_pool
71
+ @oneof_def = oneof_def
72
+ end
73
+
74
+ def self.private_constructor(oneof_def, descriptor_pool)
75
+ instance = allocate
76
+ instance.send(:initialize, oneof_def, descriptor_pool)
77
+ instance
78
+ end
79
+ end
80
+
81
+ class FFI
82
+ # MessageDef
83
+ attach_function :get_oneof_by_name, :upb_MessageDef_FindOneofByNameWithSize, [Descriptor, :string, :size_t], OneofDescriptor
84
+ attach_function :get_oneof_by_index, :upb_MessageDef_Oneof, [Descriptor, :int], OneofDescriptor
85
+
86
+ # OneofDescriptor
87
+ attach_function :get_oneof_name, :upb_OneofDef_Name, [OneofDescriptor], :string
88
+ attach_function :get_oneof_field_count, :upb_OneofDef_FieldCount, [OneofDescriptor], :int
89
+ attach_function :get_oneof_field_by_index, :upb_OneofDef_Field, [OneofDescriptor, :int], FieldDescriptor
90
+ attach_function :get_oneof_containing_type,:upb_OneofDef_ContainingType, [:pointer], Descriptor
91
+ attach_function :oneof_options, :OneOfDescriptor_serialized_options, [OneofDescriptor, :pointer, Internal::Arena], :pointer
92
+
93
+ # FieldDescriptor
94
+ attach_function :real_containing_oneof, :upb_FieldDef_RealContainingOneof, [FieldDescriptor], OneofDescriptor
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,385 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2008 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ #
9
+ # This class makes RepeatedField act (almost-) like a Ruby Array.
10
+ # It has convenience methods that extend the core C or Java based
11
+ # methods.
12
+ #
13
+ # This is a best-effort to mirror Array behavior. Two comments:
14
+ # 1) patches always welcome :)
15
+ # 2) if performance is an issue, feel free to rewrite the method
16
+ # in C. The source code has plenty of examples
17
+ #
18
+ # KNOWN ISSUES
19
+ # - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'`
20
+ # - #concat should return the orig array
21
+ # - #push should accept multiple arguments and push them all at the same time
22
+ #
23
+ module Google
24
+ module Protobuf
25
+ class FFI
26
+ # Array
27
+ attach_function :append_array, :upb_Array_Append, [:Array, MessageValue.by_value, Internal::Arena], :bool
28
+ attach_function :get_msgval_at,:upb_Array_Get, [:Array, :size_t], MessageValue.by_value
29
+ attach_function :create_array, :upb_Array_New, [Internal::Arena, CType], :Array
30
+ attach_function :array_resize, :upb_Array_Resize, [:Array, :size_t, Internal::Arena], :bool
31
+ attach_function :array_set, :upb_Array_Set, [:Array, :size_t, MessageValue.by_value], :void
32
+ attach_function :array_size, :upb_Array_Size, [:Array], :size_t
33
+ end
34
+
35
+ class RepeatedField
36
+ include Enumerable
37
+
38
+ ##
39
+ # call-seq:
40
+ # RepeatedField.new(type, type_class = nil, initial_values = [])
41
+ #
42
+ # Creates a new repeated field. The provided type must be a Ruby symbol, and
43
+ # an take on the same values as those accepted by FieldDescriptor#type=. If
44
+ # the type is :message or :enum, type_class must be non-nil, and must be the
45
+ # Ruby class or module returned by Descriptor#msgclass or
46
+ # EnumDescriptor#enummodule, respectively. An initial list of elements may also
47
+ # be provided.
48
+ def self.new(type, type_class = nil, initial_values = [])
49
+ instance = allocate
50
+ # TODO This argument mangling doesn't agree with the type signature in the comments
51
+ # but is required to make unit tests pass;
52
+ if type_class.is_a?(Enumerable) and initial_values.empty? and ![:enum, :message].include?(type)
53
+ initial_values = type_class
54
+ type_class = nil
55
+ end
56
+ instance.send(:initialize, type, type_class: type_class, initial_values: initial_values)
57
+ instance
58
+ end
59
+
60
+ ##
61
+ # call-seq:
62
+ # RepeatedField.each(&block)
63
+ #
64
+ # Invokes the block once for each element of the repeated field. RepeatedField
65
+ # also includes Enumerable; combined with this method, the repeated field thus
66
+ # acts like an ordinary Ruby sequence.
67
+ def each &block
68
+ each_msg_val do |element|
69
+ yield(convert_upb_to_ruby(element, type, descriptor, arena))
70
+ end
71
+ self
72
+ end
73
+
74
+ def [](*args)
75
+ count = length
76
+ if args.size < 1
77
+ raise ArgumentError.new "Index or range is a required argument."
78
+ end
79
+ if args[0].is_a? Range
80
+ if args.size > 1
81
+ raise ArgumentError.new "Expected 1 when passing Range argument, but got #{args.size}"
82
+ end
83
+ range = args[0]
84
+ # Handle begin-less and/or endless ranges, when supported.
85
+ index_of_first = range.respond_to?(:begin) ? range.begin : range.last
86
+ index_of_first = 0 if index_of_first.nil?
87
+ end_of_range = range.respond_to?(:end) ? range.end : range.last
88
+ index_of_last = end_of_range.nil? ? -1 : end_of_range
89
+
90
+ if index_of_last < 0
91
+ index_of_last += count
92
+ end
93
+ unless range.exclude_end? and !end_of_range.nil?
94
+ index_of_last += 1
95
+ end
96
+ index_of_first += count if index_of_first < 0
97
+ length = index_of_last - index_of_first
98
+ return [] if length.zero?
99
+ elsif args[0].is_a? Integer
100
+ index_of_first = args[0]
101
+ index_of_first += count if index_of_first < 0
102
+ if args.size > 2
103
+ raise ArgumentError.new "Expected 1 or 2 arguments, but got #{args.size}"
104
+ end
105
+ if args.size == 1 # No length specified, return one element
106
+ if array.null? or index_of_first < 0 or index_of_first >= count
107
+ return nil
108
+ else
109
+ return convert_upb_to_ruby(Google::Protobuf::FFI.get_msgval_at(array, index_of_first), type, descriptor, arena)
110
+ end
111
+ else
112
+ length = [args[1],count].min
113
+ end
114
+ else
115
+ raise NotImplementedError
116
+ end
117
+
118
+ if array.null? or index_of_first < 0 or index_of_first >= count
119
+ nil
120
+ else
121
+ if index_of_first + length > count
122
+ length = count - index_of_first
123
+ end
124
+ if length < 0
125
+ nil
126
+ else
127
+ subarray(index_of_first, length)
128
+ end
129
+ end
130
+ end
131
+ alias at []
132
+
133
+
134
+ def []=(index, value)
135
+ raise FrozenError if frozen?
136
+ count = length
137
+ index += count if index < 0
138
+ return nil if index < 0
139
+ if index >= count
140
+ resize(index+1)
141
+ empty_message_value = Google::Protobuf::FFI::MessageValue.new # Implicitly clear
142
+ count.upto(index-1) do |i|
143
+ Google::Protobuf::FFI.array_set(array, i, empty_message_value)
144
+ end
145
+ end
146
+ Google::Protobuf::FFI.array_set(array, index, convert_ruby_to_upb(value, arena, type, descriptor))
147
+ nil
148
+ end
149
+
150
+ def push(*elements)
151
+ raise FrozenError if frozen?
152
+ internal_push(*elements)
153
+ end
154
+
155
+ def <<(element)
156
+ raise FrozenError if frozen?
157
+ push element
158
+ end
159
+
160
+ def replace(replacements)
161
+ raise FrozenError if frozen?
162
+ clear
163
+ push(*replacements)
164
+ end
165
+
166
+ def clear
167
+ raise FrozenError if frozen?
168
+ resize 0
169
+ self
170
+ end
171
+
172
+ def length
173
+ array.null? ? 0 : Google::Protobuf::FFI.array_size(array)
174
+ end
175
+ alias size :length
176
+
177
+ def freeze
178
+ return self if frozen?
179
+ super
180
+ @arena.pin self
181
+ if type == :message
182
+ each do |element|
183
+ element.freeze
184
+ end
185
+ end
186
+ self
187
+ end
188
+
189
+ def dup
190
+ instance = self.class.allocate
191
+ instance.send(:initialize, type, descriptor: descriptor, arena: arena)
192
+ each_msg_val do |element|
193
+ instance.send(:append_msg_val, element)
194
+ end
195
+ instance
196
+ end
197
+ alias clone dup
198
+
199
+ def ==(other)
200
+ return true if other.object_id == object_id
201
+ if other.is_a? RepeatedField
202
+ return false unless other.length == length
203
+ each_msg_val_with_index do |msg_val, i|
204
+ other_msg_val = Google::Protobuf::FFI.get_msgval_at(other.send(:array), i)
205
+ unless Google::Protobuf::FFI.message_value_equal(msg_val, other_msg_val, type, descriptor)
206
+ return false
207
+ end
208
+ end
209
+ return true
210
+ elsif other.is_a? Enumerable
211
+ return to_ary == other.to_a
212
+ end
213
+ false
214
+ end
215
+
216
+ ##
217
+ # call-seq:
218
+ # RepeatedField.to_ary => array
219
+ #
220
+ # Used when converted implicitly into array, e.g. compared to an Array.
221
+ # Also called as a fallback of Object#to_a
222
+ def to_ary
223
+ return_value = []
224
+ each do |element|
225
+ return_value << element
226
+ end
227
+ return_value
228
+ end
229
+
230
+ def hash
231
+ return_value = 0
232
+ each_msg_val do |msg_val|
233
+ return_value = Google::Protobuf::FFI.message_value_hash(msg_val, type, descriptor, return_value)
234
+ end
235
+ return_value
236
+ end
237
+
238
+ def +(other)
239
+ if other.is_a? RepeatedField
240
+ if type != other.instance_variable_get(:@type) or descriptor != other.instance_variable_get(:@descriptor)
241
+ raise ArgumentError.new "Attempt to append RepeatedField with different element type."
242
+ end
243
+ fuse_arena(other.send(:arena))
244
+ super_set = dup
245
+ other.send(:each_msg_val) do |msg_val|
246
+ super_set.send(:append_msg_val, msg_val)
247
+ end
248
+ super_set
249
+ elsif other.is_a? Enumerable
250
+ super_set = dup
251
+ super_set.push(*other.to_a)
252
+ else
253
+ raise ArgumentError.new "Unknown type appending to RepeatedField"
254
+ end
255
+ end
256
+
257
+ def concat(other)
258
+ raise ArgumentError.new "Expected Enumerable, but got #{other.class}" unless other.is_a? Enumerable
259
+ push(*other.to_a)
260
+ end
261
+
262
+ private
263
+ include Google::Protobuf::Internal::Convert
264
+
265
+ attr :name, :arena, :array, :type, :descriptor
266
+
267
+ def internal_push(*elements)
268
+ elements.each do |element|
269
+ append_msg_val convert_ruby_to_upb(element, arena, type, descriptor)
270
+ end
271
+ self
272
+ end
273
+
274
+ def pop_one
275
+ raise FrozenError if frozen?
276
+ count = length
277
+ return nil if length.zero?
278
+ last_element = Google::Protobuf::FFI.get_msgval_at(array, count-1)
279
+ return_value = convert_upb_to_ruby(last_element, type, descriptor, arena)
280
+ resize(count-1)
281
+ return_value
282
+ end
283
+
284
+ def subarray(start, length)
285
+ return_result = []
286
+ (start..(start + length - 1)).each do |i|
287
+ element = Google::Protobuf::FFI.get_msgval_at(array, i)
288
+ return_result << convert_upb_to_ruby(element, type, descriptor, arena)
289
+ end
290
+ return_result
291
+ end
292
+
293
+ def each_msg_val_with_index &block
294
+ n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array)
295
+ 0.upto(n-1) do |i|
296
+ yield Google::Protobuf::FFI.get_msgval_at(array, i), i
297
+ end
298
+ end
299
+
300
+ def each_msg_val &block
301
+ each_msg_val_with_index do |msg_val, _|
302
+ yield msg_val
303
+ end
304
+ end
305
+
306
+ # @param msg_val [Google::Protobuf::FFI::MessageValue] Value to append
307
+ def append_msg_val(msg_val)
308
+ unless Google::Protobuf::FFI.append_array(array, msg_val, arena)
309
+ raise NoMemoryError.new "Could not allocate room for #{msg_val} in Arena"
310
+ end
311
+ end
312
+
313
+ # @param new_size [Integer] New size of the array
314
+ def resize(new_size)
315
+ unless Google::Protobuf::FFI.array_resize(array, new_size, arena)
316
+ raise NoMemoryError.new "Array resize to #{new_size} failed!"
317
+ end
318
+ end
319
+
320
+ def initialize(type, type_class: nil, initial_values: nil, name: nil, arena: nil, array: nil, descriptor: nil)
321
+ @name = name || 'RepeatedField'
322
+ raise ArgumentError.new "Expected argument type to be a Symbol" unless type.is_a? Symbol
323
+ field_number = Google::Protobuf::FFI::FieldType[type]
324
+ raise ArgumentError.new "Unsupported type '#{type}'" if field_number.nil?
325
+ if !descriptor.nil?
326
+ @descriptor = descriptor
327
+ elsif [:message, :enum].include? type
328
+ raise ArgumentError.new "Expected at least 2 arguments for message/enum." if type_class.nil?
329
+ descriptor = type_class.respond_to?(:descriptor) ? type_class.descriptor : nil
330
+ raise ArgumentError.new "Type class #{type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil?
331
+ @descriptor = descriptor
332
+ else
333
+ @descriptor = nil
334
+ end
335
+ @type = type
336
+
337
+ @arena = arena || Google::Protobuf::FFI.create_arena
338
+ @array = array || Google::Protobuf::FFI.create_array(@arena, @type)
339
+ unless initial_values.nil?
340
+ unless initial_values.is_a? Enumerable
341
+ raise ArgumentError.new "Expected array as initializer value for repeated field '#{name}' (given #{initial_values.class})."
342
+ end
343
+ internal_push(*initial_values)
344
+ end
345
+
346
+ # Should always be the last expression of the initializer to avoid
347
+ # leaking references to this object before construction is complete.
348
+ OBJECT_CACHE.try_add(@array.address, self)
349
+ end
350
+
351
+ # @param field [FieldDescriptor] Descriptor of the field where the RepeatedField will be assigned
352
+ # @param values [Enumerable] Initial values; may be nil or empty
353
+ # @param arena [Arena] Owning message's arena
354
+ def self.construct_for_field(field, arena, values: nil, array: nil)
355
+ instance = allocate
356
+ options = {initial_values: values, name: field.name, arena: arena, array: array}
357
+ if [:enum, :message].include? field.type
358
+ options[:descriptor] = field.subtype
359
+ end
360
+ instance.send(:initialize, field.type, **options)
361
+ instance
362
+ end
363
+
364
+ def fuse_arena(arena)
365
+ arena.fuse(arena)
366
+ end
367
+
368
+ extend Google::Protobuf::Internal::Convert
369
+
370
+ def self.deep_copy(repeated_field)
371
+ instance = allocate
372
+ instance.send(:initialize, repeated_field.send(:type), descriptor: repeated_field.send(:descriptor))
373
+ instance.send(:resize, repeated_field.length)
374
+ new_array = instance.send(:array)
375
+ repeated_field.send(:each_msg_val_with_index) do |element, i|
376
+ Google::Protobuf::FFI.array_set(new_array, i, message_value_deep_copy(element, repeated_field.send(:type), repeated_field.send(:descriptor), instance.send(:arena)))
377
+ end
378
+ instance
379
+ end
380
+
381
+ end
382
+ end
383
+ end
384
+
385
+ require 'google/protobuf/repeated_field'