google-protobuf 3.25.0 → 4.28.3

Sign up to get free protection for your applications and to get access to all the features.
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 -25
  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 +130 -100
  9. data/ext/google/protobuf_c/message.h +8 -5
  10. data/ext/google/protobuf_c/protobuf.c +30 -15
  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 +13047 -10836
  15. data/ext/google/protobuf_c/ruby-upb.h +11112 -9026
  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 +3 -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 +196 -56
  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
@@ -19,10 +19,14 @@ module Google
19
19
  attach_function :encode_message, :upb_Encode, [:Message, MiniTable.by_ref, :size_t, Internal::Arena, :pointer, :pointer], EncodeStatus
20
20
  attach_function :json_decode_message, :upb_JsonDecode, [:binary_string, :size_t, :Message, Descriptor, :DefPool, :int, Internal::Arena, Status.by_ref], :bool
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
@@ -293,42 +329,136 @@ module Google
293
329
 
294
330
  include Google::Protobuf::Internal::Convert
295
331
 
332
+ ##
333
+ # Checks ObjectCache for a sentinel empty frozen Map of the key and
334
+ # value types matching the field descriptor's MessageDef and returns
335
+ # the cache entry. If an entry is not found, one is created and added
336
+ # to the cache keyed by the MessageDef pointer first.
337
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
338
+ def empty_frozen_map(field_descriptor)
339
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
340
+ frozen_map = OBJECT_CACHE.get sub_message_def
341
+ if frozen_map.nil?
342
+ frozen_map = Google::Protobuf::Map.send(:construct_for_field, field_descriptor)
343
+ OBJECT_CACHE.try_add(sub_message_def, frozen_map.freeze)
344
+ end
345
+ raise "Empty Frozen Map is not frozen" unless frozen_map.frozen?
346
+ frozen_map
347
+ end
348
+
349
+ ##
350
+ # Returns a frozen Map instance for the given field. If the message
351
+ # already has a value for that field, it is used. If not, a sentinel
352
+ # (per FieldDescriptor) empty frozen Map is returned instead.
353
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
354
+ def frozen_map_from_field_descriptor(field_descriptor)
355
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
356
+ return empty_frozen_map field_descriptor if message_value[:map_val].null?
357
+ get_map_field(message_value[:map_val], field_descriptor).freeze
358
+ end
359
+
360
+ ##
361
+ # Returns a Map instance for the given field. If the message is frozen
362
+ # the return value is also frozen. If not, a mutable instance is
363
+ # returned instead.
364
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
365
+ def map_from_field_descriptor(field_descriptor)
366
+ return frozen_map_from_field_descriptor field_descriptor if frozen?
367
+ mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
368
+ get_map_field(mutable_message_value[:map], field_descriptor)
369
+ end
370
+
371
+ ##
372
+ # Checks ObjectCache for a sentinel empty frozen RepeatedField of the
373
+ # value type matching the field descriptor's MessageDef and returns
374
+ # the cache entry. If an entry is not found, one is created and added
375
+ # to the cache keyed by the MessageDef pointer first.
376
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
377
+ def empty_frozen_repeated_field(field_descriptor)
378
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
379
+ frozen_repeated_field = OBJECT_CACHE.get sub_message_def
380
+ if frozen_repeated_field.nil?
381
+ frozen_repeated_field = Google::Protobuf::RepeatedField.send(:construct_for_field, field_descriptor)
382
+ OBJECT_CACHE.try_add(sub_message_def, frozen_repeated_field.freeze)
383
+ end
384
+ raise "Empty frozen RepeatedField is not frozen" unless frozen_repeated_field.frozen?
385
+ frozen_repeated_field
386
+ end
387
+
388
+ ##
389
+ # Returns a frozen RepeatedField instance for the given field. If the
390
+ # message already has a value for that field, it is used. If not, a
391
+ # sentinel (per FieldDescriptor) empty frozen RepeatedField is
392
+ # returned instead.
393
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
394
+ def frozen_repeated_field_from_field_descriptor(field_descriptor)
395
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
396
+ return empty_frozen_repeated_field field_descriptor if message_value[:array_val].null?
397
+ get_repeated_field(message_value[:array_val], field_descriptor).freeze
398
+ end
399
+
400
+ ##
401
+ # Returns a RepeatedField instance for the given field. If the message
402
+ # is frozen the return value is also frozen. If not, a mutable
403
+ # instance is returned instead.
404
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
405
+ def repeated_field_from_field_descriptor(field_descriptor)
406
+ return frozen_repeated_field_from_field_descriptor field_descriptor if frozen?
407
+ mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
408
+ get_repeated_field(mutable_message_value[:array], field_descriptor)
409
+ end
410
+
411
+ ##
412
+ # Returns a Message instance for the given field. If the message
413
+ # is frozen nil is always returned. Otherwise, a mutable instance is
414
+ # returned instead.
415
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
416
+ def message_from_field_descriptor(field_descriptor)
417
+ return nil if frozen?
418
+ return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor
419
+ mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
420
+ sub_message = mutable_message[:msg]
421
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor
422
+ Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
423
+ end
424
+
425
+ ##
426
+ # Returns a scalar value for the given field. If the message
427
+ # is frozen the return value is also frozen.
428
+ # @param field_descriptor [FieldDescriptor] Field to retrieve.
429
+ def scalar_from_field_descriptor(field_descriptor)
430
+ c_type = field_descriptor.send(:c_type)
431
+ message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
432
+ msg_or_enum_def = c_type == :enum ? Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor) : nil
433
+ return_value = convert_upb_to_ruby message_value, c_type, msg_or_enum_def
434
+ frozen? ? return_value.freeze : return_value
435
+ end
436
+
437
+ ##
438
+ # Dynamically define accessors methods for every field of @descriptor.
439
+ # Methods with names that conflict with existing methods are skipped.
296
440
  def self.setup_accessors!
297
441
  @descriptor.each do |field_descriptor|
298
442
  field_name = field_descriptor.name
299
443
  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.
444
+ # Dispatching to either index_internal or get_field is logically
445
+ # correct, but slightly slower due to having to perform extra
446
+ # lookups on each invocation rather than doing it once here.
302
447
  if field_descriptor.map?
303
448
  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)
449
+ map_from_field_descriptor field_descriptor
306
450
  end
307
451
  elsif field_descriptor.repeated?
308
452
  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)
453
+ repeated_field_from_field_descriptor field_descriptor
311
454
  end
312
455
  elsif field_descriptor.sub_message?
313
456
  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)
457
+ message_from_field_descriptor field_descriptor
319
458
  end
320
459
  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
460
+ define_method(field_name) do
461
+ scalar_from_field_descriptor field_descriptor
332
462
  end
333
463
  end
334
464
  define_method("#{field_name}=") do |value|
@@ -338,14 +468,16 @@ module Google
338
468
  clear_internal(field_descriptor)
339
469
  end
340
470
  if field_descriptor.type == :enum
341
- define_method("#{field_name}_const") do
342
- if field_descriptor.repeated?
471
+ if field_descriptor.repeated?
472
+ define_method("#{field_name}_const") do
343
473
  return_value = []
344
- get_field(field_descriptor).send(:each_msg_val) do |msg_val|
474
+ repeated_field_from_field_descriptor(field_descriptor).send(:each_msg_val) do |msg_val|
345
475
  return_value << msg_val[:int32_val]
346
476
  end
347
477
  return_value
348
- else
478
+ end
479
+ else
480
+ define_method("#{field_name}_const") do
349
481
  message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
350
482
  message_value[:int32_val]
351
483
  end
@@ -372,12 +504,21 @@ module Google
372
504
  end
373
505
  end
374
506
 
507
+ ##
508
+ # Dynamically define accessors methods for every OneOf field of
509
+ # @descriptor.
375
510
  def self.setup_oneof_accessors!
376
511
  @oneof_field_names = []
377
512
  @descriptor.each_oneof do |oneof_descriptor|
378
513
  self.add_oneof_accessors_for! oneof_descriptor
379
514
  end
380
515
  end
516
+
517
+ ##
518
+ # Dynamically define accessors methods for the given OneOf field.
519
+ # Methods with names that conflict with existing methods are skipped.
520
+ # @param oneof_descriptor [OneofDescriptor] Field to create accessors
521
+ # for.
381
522
  def self.add_oneof_accessors_for!(oneof_descriptor)
382
523
  field_name = oneof_descriptor.name.to_sym
383
524
  @oneof_field_names << field_name
@@ -508,6 +649,10 @@ module Google
508
649
  Google::Protobuf::FFI.clear_message_field(@msg, field_def)
509
650
  end
510
651
 
652
+ # Accessor for field by name. Does not delegate to methods setup by
653
+ # self.setup_accessors! in order to avoid conflicts with bad field
654
+ # names e.g. `dup` or `class` which are perfectly valid for proto
655
+ # fields.
511
656
  def index_internal(name)
512
657
  field_descriptor = self.class.descriptor.lookup(name)
513
658
  get_field field_descriptor unless field_descriptor.nil?
@@ -535,7 +680,7 @@ module Google
535
680
  # one if omitted or nil.
536
681
  def initialize(initial_value = nil, arena = nil, msg = nil)
537
682
  @arena = arena || Google::Protobuf::FFI.create_arena
538
- @msg = msg || Google::Protobuf::FFI.new_message_from_def(self.class.descriptor, @arena)
683
+ @msg = msg || Google::Protobuf::FFI.new_message_from_def(Google::Protobuf::FFI.get_mini_table(self.class.descriptor), @arena)
539
684
 
540
685
  unless initial_value.nil?
541
686
  raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each
@@ -556,9 +701,9 @@ module Google
556
701
 
557
702
  next if value.nil?
558
703
  if field_descriptor.map?
559
- index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, @arena, value: value), name: key.to_s)
704
+ index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, arena: @arena, value: value), name: key.to_s)
560
705
  elsif field_descriptor.repeated?
561
- index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, @arena, values: value), name: key.to_s)
706
+ index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, arena: @arena, values: value), name: key.to_s)
562
707
  else
563
708
  index_assign_internal(value, name: key.to_s)
564
709
  end
@@ -571,21 +716,20 @@ module Google
571
716
  end
572
717
 
573
718
  ##
574
- # Gets a field of this message identified by the argument definition.
719
+ # Gets a field of this message identified by FieldDescriptor.
575
720
  #
576
- # @param field [FieldDescriptor] Descriptor of the field to get
721
+ # @param field [FieldDescriptor] Field to retrieve.
722
+ # @param unwrap [Boolean](false) If true, unwraps wrappers.
577
723
  def get_field(field, unwrap: false)
578
724
  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)
725
+ map_from_field_descriptor field
581
726
  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)
727
+ repeated_field_from_field_descriptor field
584
728
  elsif field.sub_message?
585
729
  return nil unless Google::Protobuf::FFI.get_message_has @msg, field
586
- sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field)
587
730
  if unwrap
588
731
  if field.has?(self)
732
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field
589
733
  wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field
590
734
  fields = Google::Protobuf::FFI.field_count(sub_message_def)
591
735
  raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1
@@ -596,41 +740,37 @@ module Google
596
740
  nil
597
741
  end
598
742
  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)
743
+ message_from_field_descriptor field
602
744
  end
603
745
  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
746
+ scalar_from_field_descriptor field
611
747
  end
612
748
  end
613
749
 
614
750
  ##
615
- # @param array [::FFI::Pointer] Pointer to the Array
751
+ # Gets a RepeatedField from the ObjectCache or creates a new one.
752
+ # @param array [::FFI::Pointer] Pointer to the upb_Array
616
753
  # @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field
617
754
  def get_repeated_field(array, field)
618
755
  return nil if array.nil? or array.null?
619
756
  repeated_field = OBJECT_CACHE.get(array.address)
620
757
  if repeated_field.nil?
621
- repeated_field = RepeatedField.send(:construct_for_field, field, @arena, array: array)
758
+ repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array)
759
+ repeated_field.freeze if frozen?
622
760
  end
623
761
  repeated_field
624
762
  end
625
763
 
626
764
  ##
627
- # @param map [::FFI::Pointer] Pointer to the Map
765
+ # Gets a Map from the ObjectCache or creates a new one.
766
+ # @param map [::FFI::Pointer] Pointer to the upb_Map
628
767
  # @param field [Google::Protobuf::FieldDescriptor] Type of the map field
629
768
  def get_map_field(map, field)
630
769
  return nil if map.nil? or map.null?
631
770
  map_field = OBJECT_CACHE.get(map.address)
632
771
  if map_field.nil?
633
- map_field = Google::Protobuf::Map.send(:construct_for_field, field, @arena, map: map)
772
+ map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map)
773
+ map_field.freeze if frozen?
634
774
  end
635
775
  map_field
636
776
  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
@@ -22,10 +22,7 @@ module Google
22
22
  # @param value [OneofDescriptor] FieldDescriptor to convert to an FFI native type
23
23
  # @param _ [Object] Unused
24
24
  def to_native(value, _ = nil)
25
- oneof_def_ptr = value.instance_variable_get(:@oneof_def)
26
- warn "Underlying oneof_def was nil!" if oneof_def_ptr.nil?
27
- raise "Underlying oneof_def was null!" if !oneof_def_ptr.nil? and oneof_def_ptr.null?
28
- oneof_def_ptr
25
+ value.instance_variable_get(:@oneof_def) || ::FFI::Pointer::NULL
29
26
  end
30
27
 
31
28
  ##
@@ -56,6 +53,17 @@ module Google
56
53
  nil
57
54
  end
58
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
+
59
67
  private
60
68
 
61
69
  def initialize(oneof_def, descriptor_pool)
@@ -72,17 +80,18 @@ module Google
72
80
 
73
81
  class FFI
74
82
  # MessageDef
75
- attach_function :get_oneof_by_name, :upb_MessageDef_FindOneofByNameWithSize, [Descriptor, :string, :size_t], OneofDescriptor
76
- attach_function :get_oneof_by_index, :upb_MessageDef_Oneof, [Descriptor, :int], OneofDescriptor
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
77
85
 
78
86
  # OneofDescriptor
79
- attach_function :get_oneof_name, :upb_OneofDef_Name, [OneofDescriptor], :string
80
- attach_function :get_oneof_field_count, :upb_OneofDef_FieldCount, [OneofDescriptor], :int
81
- attach_function :get_oneof_field_by_index, :upb_OneofDef_Field, [OneofDescriptor, :int], FieldDescriptor
82
- attach_function :get_oneof_containing_type,:upb_OneofDef_ContainingType,[:pointer], Descriptor
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
83
92
 
84
93
  # FieldDescriptor
85
- attach_function :real_containing_oneof, :upb_FieldDef_RealContainingOneof,[FieldDescriptor], OneofDescriptor
94
+ attach_function :real_containing_oneof, :upb_FieldDef_RealContainingOneof, [FieldDescriptor], OneofDescriptor
86
95
  end
87
96
  end
88
97
  end