google-protobuf 3.25.0 → 4.29.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +46 -18
  3. data/ext/google/protobuf_c/defs.c +499 -26
  4. data/ext/google/protobuf_c/extconf.rb +1 -1
  5. data/ext/google/protobuf_c/glue.c +53 -2
  6. data/ext/google/protobuf_c/map.c +82 -17
  7. data/ext/google/protobuf_c/map.h +9 -2
  8. data/ext/google/protobuf_c/message.c +144 -104
  9. data/ext/google/protobuf_c/message.h +8 -5
  10. data/ext/google/protobuf_c/protobuf.c +30 -17
  11. data/ext/google/protobuf_c/protobuf.h +3 -7
  12. data/ext/google/protobuf_c/repeated_field.c +64 -10
  13. data/ext/google/protobuf_c/repeated_field.h +8 -1
  14. data/ext/google/protobuf_c/ruby-upb.c +13774 -11526
  15. data/ext/google/protobuf_c/ruby-upb.h +11198 -9048
  16. data/ext/google/protobuf_c/shared_convert.c +10 -5
  17. data/ext/google/protobuf_c/shared_convert.h +2 -2
  18. data/ext/google/protobuf_c/shared_message.c +3 -31
  19. data/ext/google/protobuf_c/shared_message.h +0 -4
  20. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
  21. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -8
  22. data/lib/google/protobuf/any_pb.rb +1 -22
  23. data/lib/google/protobuf/api_pb.rb +1 -24
  24. data/lib/google/protobuf/descriptor_pb.rb +3 -23
  25. data/lib/google/protobuf/duration_pb.rb +1 -22
  26. data/lib/google/protobuf/empty_pb.rb +1 -22
  27. data/lib/google/protobuf/ffi/descriptor.rb +13 -2
  28. data/lib/google/protobuf/ffi/descriptor_pool.rb +16 -9
  29. data/lib/google/protobuf/ffi/enum_descriptor.rb +13 -1
  30. data/lib/google/protobuf/ffi/ffi.rb +8 -6
  31. data/lib/google/protobuf/ffi/field_descriptor.rb +37 -16
  32. data/lib/google/protobuf/ffi/file_descriptor.rb +13 -12
  33. data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
  34. data/lib/google/protobuf/ffi/internal/convert.rb +21 -30
  35. data/lib/google/protobuf/ffi/map.rb +50 -13
  36. data/lib/google/protobuf/ffi/message.rb +202 -58
  37. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  38. data/lib/google/protobuf/ffi/object_cache.rb +3 -3
  39. data/lib/google/protobuf/ffi/oneof_descriptor.rb +20 -11
  40. data/lib/google/protobuf/ffi/repeated_field.rb +50 -142
  41. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  42. data/lib/google/protobuf/field_mask_pb.rb +1 -22
  43. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  44. data/lib/google/protobuf/plugin_pb.rb +2 -24
  45. data/lib/google/protobuf/repeated_field.rb +4 -5
  46. data/lib/google/protobuf/source_context_pb.rb +1 -22
  47. data/lib/google/protobuf/struct_pb.rb +1 -22
  48. data/lib/google/protobuf/timestamp_pb.rb +1 -22
  49. data/lib/google/protobuf/type_pb.rb +1 -24
  50. data/lib/google/protobuf/wrappers_pb.rb +1 -22
  51. data/lib/google/protobuf.rb +1 -1
  52. data/lib/google/protobuf_ffi.rb +3 -2
  53. data/lib/google/protobuf_native.rb +0 -1
  54. data/lib/google/tasks/ffi.rake +1 -3
  55. metadata +25 -12
  56. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  57. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  58. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  59. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  60. data/lib/google/protobuf/object_cache.rb +0 -97
@@ -9,18 +9,20 @@ module Google
9
9
  module Protobuf
10
10
  class FFI
11
11
  # Map
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
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, :upb_MapIterator_Next, [:Map, :pointer], :bool
21
- attach_function :map_done, :upb_MapIterator_Done, [:Map, :size_t], :bool
22
- attach_function :map_key, :upb_MapIterator_Key, [:Map, :size_t], MessageValue.by_value
23
- attach_function :map_value, :upb_MapIterator_Value, [:Map, :size_t], MessageValue.by_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,6 +157,37 @@ 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.
177
+ def 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"
181
+ end
182
+ return self
183
+ end
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
189
+ end
190
+
158
191
  ##
159
192
  # call-seq:
160
193
  # Map.dup => new_map
@@ -358,10 +391,14 @@ module Google
358
391
  OBJECT_CACHE.try_add(@map_ptr.address, self)
359
392
  end
360
393
 
361
- # @param field [FieldDescriptor] Descriptor of the field where the RepeatedField will be assigned
362
- # @param values [Hash|Map] Initial value; may be nil or empty
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
363
398
  # @param arena [Arena] Owning message's arena
364
- def self.construct_for_field(field, arena, value: nil, map: nil)
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)
365
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
366
403
  instance = allocate
367
404
  raise ArgumentError.new "Expected field with type :message, instead got #{field.class}" unless field.type == :message
@@ -17,12 +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 :json_decode_message, :upb_JsonDecode, [:binary_string, :size_t, :Message, Descriptor, :DefPool, :int, Internal::Arena, Status.by_ref], :bool
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
- attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus
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, :upb_Message_WhichOneof, [:Message, OneofDescriptor], FieldDescriptor
24
+ attach_function :get_message_which_oneof, :upb_Message_WhichOneofByDef, [:Message, OneofDescriptor], FieldDescriptor
25
25
  attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :int], :bool
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
+
26
30
  # MessageValue
27
31
  attach_function :message_value_equal, :shared_Msgval_IsEqual, [MessageValue.by_value, MessageValue.by_value, CType, Descriptor], :bool
28
32
  attach_function :message_value_hash, :shared_Msgval_GetHash, [MessageValue.by_value, CType, Descriptor, :uint64_t], :uint64_t
@@ -57,11 +61,35 @@ module Google
57
61
  instance
58
62
  end
59
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.
60
81
  def 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"
85
+ end
86
+ return self
87
+ end
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
61
91
  super
62
- @arena.pin self
63
- self
64
- end
92
+ end
65
93
 
66
94
  def dup
67
95
  duplicate = self.class.private_constructor(@arena)
@@ -170,7 +198,15 @@ module Google
170
198
 
171
199
  message = new
172
200
  mini_table_ptr = Google::Protobuf::FFI.get_mini_table(message.class.descriptor)
173
- status = Google::Protobuf::FFI.decode_message(data, data.bytesize, message.instance_variable_get(:@msg), mini_table_ptr, nil, decoding_options, message.instance_variable_get(:@arena))
201
+ status = Google::Protobuf::FFI.decode_message(
202
+ data,
203
+ data.bytesize,
204
+ message.instance_variable_get(:@msg),
205
+ mini_table_ptr,
206
+ Google::Protobuf::FFI.get_extension_registry(message.class.descriptor.send(:pool).descriptor_pool),
207
+ decoding_options,
208
+ message.instance_variable_get(:@arena)
209
+ )
174
210
  raise ParseError.new "Error occurred during parsing" unless status == :Ok
175
211
  message
176
212
  end
@@ -234,7 +270,11 @@ module Google
234
270
  message = new
235
271
  pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool
236
272
  status = Google::Protobuf::FFI::Status.new
237
- unless Google::Protobuf::FFI.json_decode_message(data, data.bytesize, message.instance_variable_get(:@msg), message.class.descriptor, pool_def, decoding_options, message.instance_variable_get(:@arena), status)
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_OkWithEmptyStringNumerics
276
+ warn Google::Protobuf::FFI.error_message(status)
277
+ when Google::Protobuf::FFI::Upb_JsonDecodeResult_Error
238
278
  raise ParseError.new "Error occurred during parsing: #{Google::Protobuf::FFI.error_message(status)}"
239
279
  end
240
280
  message
@@ -293,42 +333,136 @@ module Google
293
333
 
294
334
  include Google::Protobuf::Internal::Convert
295
335
 
336
+ ##
337
+ # Checks ObjectCache for a sentinel empty frozen Map of the key and
338
+ # value types matching the field descriptor's MessageDef and returns
339
+ # the cache entry. If an entry is not found, one is created and added
340
+ # to the cache keyed by the MessageDef pointer first.
341
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
342
+ def empty_frozen_map(field_descriptor)
343
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
344
+ frozen_map = OBJECT_CACHE.get sub_message_def
345
+ if frozen_map.nil?
346
+ frozen_map = Google::Protobuf::Map.send(:construct_for_field, field_descriptor)
347
+ OBJECT_CACHE.try_add(sub_message_def, frozen_map.freeze)
348
+ end
349
+ raise "Empty Frozen Map is not frozen" unless frozen_map.frozen?
350
+ frozen_map
351
+ end
352
+
353
+ ##
354
+ # Returns a frozen Map instance for the given field. If the message
355
+ # already has a value for that field, it is used. If not, a sentinel
356
+ # (per FieldDescriptor) empty frozen Map is returned instead.
357
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
358
+ def frozen_map_from_field_descriptor(field_descriptor)
359
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
360
+ return empty_frozen_map field_descriptor if message_value[:map_val].null?
361
+ get_map_field(message_value[:map_val], field_descriptor).freeze
362
+ end
363
+
364
+ ##
365
+ # Returns a Map instance for the given field. If the message is frozen
366
+ # the return value is also frozen. If not, a mutable instance is
367
+ # returned instead.
368
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
369
+ def map_from_field_descriptor(field_descriptor)
370
+ return frozen_map_from_field_descriptor field_descriptor if frozen?
371
+ mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
372
+ get_map_field(mutable_message_value[:map], field_descriptor)
373
+ end
374
+
375
+ ##
376
+ # Checks ObjectCache for a sentinel empty frozen RepeatedField of the
377
+ # value type matching the field descriptor's MessageDef and returns
378
+ # the cache entry. If an entry is not found, one is created and added
379
+ # to the cache keyed by the MessageDef pointer first.
380
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
381
+ def empty_frozen_repeated_field(field_descriptor)
382
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
383
+ frozen_repeated_field = OBJECT_CACHE.get sub_message_def
384
+ if frozen_repeated_field.nil?
385
+ frozen_repeated_field = Google::Protobuf::RepeatedField.send(:construct_for_field, field_descriptor)
386
+ OBJECT_CACHE.try_add(sub_message_def, frozen_repeated_field.freeze)
387
+ end
388
+ raise "Empty frozen RepeatedField is not frozen" unless frozen_repeated_field.frozen?
389
+ frozen_repeated_field
390
+ end
391
+
392
+ ##
393
+ # Returns a frozen RepeatedField instance for the given field. If the
394
+ # message already has a value for that field, it is used. If not, a
395
+ # sentinel (per FieldDescriptor) empty frozen RepeatedField is
396
+ # returned instead.
397
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
398
+ def frozen_repeated_field_from_field_descriptor(field_descriptor)
399
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
400
+ return empty_frozen_repeated_field field_descriptor if message_value[:array_val].null?
401
+ get_repeated_field(message_value[:array_val], field_descriptor).freeze
402
+ end
403
+
404
+ ##
405
+ # Returns a RepeatedField instance for the given field. If the message
406
+ # is frozen the return value is also frozen. If not, a mutable
407
+ # instance is returned instead.
408
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
409
+ def repeated_field_from_field_descriptor(field_descriptor)
410
+ return frozen_repeated_field_from_field_descriptor field_descriptor if frozen?
411
+ mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
412
+ get_repeated_field(mutable_message_value[:array], field_descriptor)
413
+ end
414
+
415
+ ##
416
+ # Returns a Message instance for the given field. If the message
417
+ # is frozen nil is always returned. Otherwise, a mutable instance is
418
+ # returned instead.
419
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
420
+ def message_from_field_descriptor(field_descriptor)
421
+ return nil if frozen?
422
+ return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor
423
+ mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
424
+ sub_message = mutable_message[:msg]
425
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
426
+ Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
427
+ end
428
+
429
+ ##
430
+ # Returns a scalar value for the given field. If the message
431
+ # is frozen the return value is also frozen.
432
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
433
+ def scalar_from_field_descriptor(field_descriptor)
434
+ c_type = field_descriptor.send(:c_type)
435
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
436
+ msg_or_enum_def = c_type == :enum ? Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor) : nil
437
+ return_value = convert_upb_to_ruby message_value, c_type, msg_or_enum_def
438
+ frozen? ? return_value.freeze : return_value
439
+ end
440
+
441
+ ##
442
+ # Dynamically define accessors methods for every field of @descriptor.
443
+ # Methods with names that conflict with existing methods are skipped.
296
444
  def self.setup_accessors!
297
445
  @descriptor.each do |field_descriptor|
298
446
  field_name = field_descriptor.name
299
447
  unless instance_methods(true).include?(field_name.to_sym)
300
- #TODO - at a high level, dispatching to either
301
- # index_internal or get_field would be logically correct, but slightly slower.
448
+ # Dispatching to either index_internal or get_field is logically
449
+ # correct, but slightly slower due to having to perform extra
450
+ # lookups on each invocation rather than doing it once here.
302
451
  if field_descriptor.map?
303
452
  define_method(field_name) do
304
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
305
- get_map_field(mutable_message_value[:map], field_descriptor)
453
+ map_from_field_descriptor field_descriptor
306
454
  end
307
455
  elsif field_descriptor.repeated?
308
456
  define_method(field_name) do
309
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
310
- get_repeated_field(mutable_message_value[:array], field_descriptor)
457
+ repeated_field_from_field_descriptor field_descriptor
311
458
  end
312
459
  elsif field_descriptor.sub_message?
313
460
  define_method(field_name) do
314
- return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor
315
- mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
316
- sub_message = mutable_message[:msg]
317
- sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field_descriptor)
318
- Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
461
+ message_from_field_descriptor field_descriptor
319
462
  end
320
463
  else
321
- c_type = field_descriptor.send(:c_type)
322
- if c_type == :enum
323
- define_method(field_name) do
324
- message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
325
- convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor)
326
- end
327
- else
328
- define_method(field_name) do
329
- message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
330
- convert_upb_to_ruby message_value, c_type
331
- end
464
+ define_method(field_name) do
465
+ scalar_from_field_descriptor field_descriptor
332
466
  end
333
467
  end
334
468
  define_method("#{field_name}=") do |value|
@@ -338,14 +472,16 @@ module Google
338
472
  clear_internal(field_descriptor)
339
473
  end
340
474
  if field_descriptor.type == :enum
341
- define_method("#{field_name}_const") do
342
- if field_descriptor.repeated?
475
+ if field_descriptor.repeated?
476
+ define_method("#{field_name}_const") do
343
477
  return_value = []
344
- get_field(field_descriptor).send(:each_msg_val) do |msg_val|
478
+ repeated_field_from_field_descriptor(field_descriptor).send(:each_msg_val) do |msg_val|
345
479
  return_value << msg_val[:int32_val]
346
480
  end
347
481
  return_value
348
- else
482
+ end
483
+ else
484
+ define_method("#{field_name}_const") do
349
485
  message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
350
486
  message_value[:int32_val]
351
487
  end
@@ -372,12 +508,21 @@ module Google
372
508
  end
373
509
  end
374
510
 
511
+ ##
512
+ # Dynamically define accessors methods for every OneOf field of
513
+ # @descriptor.
375
514
  def self.setup_oneof_accessors!
376
515
  @oneof_field_names = []
377
516
  @descriptor.each_oneof do |oneof_descriptor|
378
517
  self.add_oneof_accessors_for! oneof_descriptor
379
518
  end
380
519
  end
520
+
521
+ ##
522
+ # Dynamically define accessors methods for the given OneOf field.
523
+ # Methods with names that conflict with existing methods are skipped.
524
+ # @param oneof_descriptor [OneofDescriptor] Field to create accessors
525
+ # for.
381
526
  def self.add_oneof_accessors_for!(oneof_descriptor)
382
527
  field_name = oneof_descriptor.name.to_sym
383
528
  @oneof_field_names << field_name
@@ -508,6 +653,10 @@ module Google
508
653
  Google::Protobuf::FFI.clear_message_field(@msg, field_def)
509
654
  end
510
655
 
656
+ # Accessor for field by name. Does not delegate to methods setup by
657
+ # self.setup_accessors! in order to avoid conflicts with bad field
658
+ # names e.g. `dup` or `class` which are perfectly valid for proto
659
+ # fields.
511
660
  def index_internal(name)
512
661
  field_descriptor = self.class.descriptor.lookup(name)
513
662
  get_field field_descriptor unless field_descriptor.nil?
@@ -535,7 +684,7 @@ module Google
535
684
  # one if omitted or nil.
536
685
  def initialize(initial_value = nil, arena = nil, msg = nil)
537
686
  @arena = arena || Google::Protobuf::FFI.create_arena
538
- @msg = msg || Google::Protobuf::FFI.new_message_from_def(self.class.descriptor, @arena)
687
+ @msg = msg || Google::Protobuf::FFI.new_message_from_def(Google::Protobuf::FFI.get_mini_table(self.class.descriptor), @arena)
539
688
 
540
689
  unless initial_value.nil?
541
690
  raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each
@@ -556,9 +705,9 @@ module Google
556
705
 
557
706
  next if value.nil?
558
707
  if field_descriptor.map?
559
- index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, @arena, value: value), name: key.to_s)
708
+ index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, arena: @arena, value: value), name: key.to_s)
560
709
  elsif field_descriptor.repeated?
561
- index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, @arena, values: value), name: key.to_s)
710
+ index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, arena: @arena, values: value), name: key.to_s)
562
711
  else
563
712
  index_assign_internal(value, name: key.to_s)
564
713
  end
@@ -571,21 +720,20 @@ module Google
571
720
  end
572
721
 
573
722
  ##
574
- # Gets a field of this message identified by the argument definition.
723
+ # Gets a field of this message identified by FieldDescriptor.
575
724
  #
576
- # @param field [FieldDescriptor] Descriptor of the field to get
725
+ # @param field [FieldDescriptor] Field to retrieve.
726
+ # @param unwrap [Boolean](false) If true, unwraps wrappers.
577
727
  def get_field(field, unwrap: false)
578
728
  if field.map?
579
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
580
- get_map_field(mutable_message_value[:map], field)
729
+ map_from_field_descriptor field
581
730
  elsif field.repeated?
582
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
583
- get_repeated_field(mutable_message_value[:array], field)
731
+ repeated_field_from_field_descriptor field
584
732
  elsif field.sub_message?
585
733
  return nil unless Google::Protobuf::FFI.get_message_has @msg, field
586
- sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field)
587
734
  if unwrap
588
735
  if field.has?(self)
736
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field
589
737
  wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field
590
738
  fields = Google::Protobuf::FFI.field_count(sub_message_def)
591
739
  raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1
@@ -596,41 +744,37 @@ module Google
596
744
  nil
597
745
  end
598
746
  else
599
- mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
600
- sub_message = mutable_message[:msg]
601
- Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
747
+ message_from_field_descriptor field
602
748
  end
603
749
  else
604
- c_type = field.send(:c_type)
605
- message_value = Google::Protobuf::FFI.get_message_value @msg, field
606
- if c_type == :enum
607
- convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field)
608
- else
609
- convert_upb_to_ruby message_value, c_type
610
- end
750
+ scalar_from_field_descriptor field
611
751
  end
612
752
  end
613
753
 
614
754
  ##
615
- # @param array [::FFI::Pointer] Pointer to the Array
755
+ # Gets a RepeatedField from the ObjectCache or creates a new one.
756
+ # @param array [::FFI::Pointer] Pointer to the upb_Array
616
757
  # @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field
617
758
  def get_repeated_field(array, field)
618
759
  return nil if array.nil? or array.null?
619
760
  repeated_field = OBJECT_CACHE.get(array.address)
620
761
  if repeated_field.nil?
621
- repeated_field = RepeatedField.send(:construct_for_field, field, @arena, array: array)
762
+ repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array)
763
+ repeated_field.freeze if frozen?
622
764
  end
623
765
  repeated_field
624
766
  end
625
767
 
626
768
  ##
627
- # @param map [::FFI::Pointer] Pointer to the Map
769
+ # Gets a Map from the ObjectCache or creates a new one.
770
+ # @param map [::FFI::Pointer] Pointer to the upb_Map
628
771
  # @param field [Google::Protobuf::FieldDescriptor] Type of the map field
629
772
  def get_map_field(map, field)
630
773
  return nil if map.nil? or map.null?
631
774
  map_field = OBJECT_CACHE.get(map.address)
632
775
  if map_field.nil?
633
- map_field = Google::Protobuf::Map.send(:construct_for_field, field, @arena, map: map)
776
+ map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map)
777
+ map_field.freeze if frozen?
634
778
  end
635
779
  map_field
636
780
  end
@@ -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
+
@@ -18,13 +18,13 @@ module Google
18
18
 
19
19
  def self.cache_implementation
20
20
  if interpreter_supports_non_finalized_keys_in_weak_map? and SIZEOF_LONG >= SIZEOF_VALUE
21
- Google::Protobuf::ObjectCache
21
+ Google::Protobuf::Internal::ObjectCache
22
22
  else
23
- Google::Protobuf::LegacyObjectCache
23
+ Google::Protobuf::Internal::LegacyObjectCache
24
24
  end
25
25
  end
26
26
 
27
27
  public
28
28
  OBJECT_CACHE = cache_implementation.new
29
29
  end
30
- end
30
+ end