google-protobuf 3.25.5 → 4.28.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

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 +368 -29
  4. data/ext/google/protobuf_c/extconf.rb +1 -1
  5. data/ext/google/protobuf_c/glue.c +16 -0
  6. data/ext/google/protobuf_c/map.c +74 -29
  7. data/ext/google/protobuf_c/map.h +7 -3
  8. data/ext/google/protobuf_c/message.c +106 -114
  9. data/ext/google/protobuf_c/message.h +2 -6
  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 +58 -23
  13. data/ext/google/protobuf_c/repeated_field.h +6 -2
  14. data/ext/google/protobuf_c/ruby-upb.c +13047 -10836
  15. data/ext/google/protobuf_c/ruby-upb.h +11114 -9028
  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 +4 -4
  28. data/lib/google/protobuf/ffi/descriptor_pool.rb +3 -1
  29. data/lib/google/protobuf/ffi/enum_descriptor.rb +3 -1
  30. data/lib/google/protobuf/ffi/ffi.rb +3 -6
  31. data/lib/google/protobuf/ffi/field_descriptor.rb +13 -2
  32. data/lib/google/protobuf/ffi/file_descriptor.rb +3 -13
  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 -24
  36. data/lib/google/protobuf/ffi/message.rb +183 -64
  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 +3 -1
  40. data/lib/google/protobuf/ffi/repeated_field.rb +47 -19
  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
@@ -21,8 +21,12 @@ module Google
21
21
  attach_function :json_encode_message, :upb_JsonEncode, [:Message, Descriptor, :DefPool, :int, :binary_string, :size_t, Status.by_ref], :size_t
22
22
  attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus
23
23
  attach_function :get_mutable_message, :upb_Message_Mutable, [:Message, FieldDescriptor, Internal::Arena], MutableMessageValue.by_value
24
- attach_function :get_message_which_oneof, :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)
@@ -301,53 +329,136 @@ module Google
301
329
 
302
330
  include Google::Protobuf::Internal::Convert
303
331
 
304
- def internal_deep_freeze
305
- freeze
306
- self.class.descriptor.each do |field_descriptor|
307
- next if field_descriptor.has_presence? && !Google::Protobuf::FFI.get_message_has(@msg, field_descriptor)
308
- if field_descriptor.map? or field_descriptor.repeated? or field_descriptor.sub_message?
309
- get_field(field_descriptor).send :internal_deep_freeze
310
- end
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)
311
344
  end
312
- self
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
313
398
  end
314
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.
315
440
  def self.setup_accessors!
316
441
  @descriptor.each do |field_descriptor|
317
442
  field_name = field_descriptor.name
318
443
  unless instance_methods(true).include?(field_name.to_sym)
319
- #TODO - at a high level, dispatching to either
320
- # 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.
321
447
  if field_descriptor.map?
322
448
  define_method(field_name) do
323
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
324
- get_map_field(mutable_message_value[:map], field_descriptor)
449
+ map_from_field_descriptor field_descriptor
325
450
  end
326
451
  elsif field_descriptor.repeated?
327
452
  define_method(field_name) do
328
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
329
- get_repeated_field(mutable_message_value[:array], field_descriptor)
453
+ repeated_field_from_field_descriptor field_descriptor
330
454
  end
331
455
  elsif field_descriptor.sub_message?
332
456
  define_method(field_name) do
333
- return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor
334
- mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena
335
- sub_message = mutable_message[:msg]
336
- sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field_descriptor)
337
- Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
457
+ message_from_field_descriptor field_descriptor
338
458
  end
339
459
  else
340
- c_type = field_descriptor.send(:c_type)
341
- if c_type == :enum
342
- define_method(field_name) do
343
- message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
344
- convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor)
345
- end
346
- else
347
- define_method(field_name) do
348
- message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
349
- convert_upb_to_ruby message_value, c_type
350
- end
460
+ define_method(field_name) do
461
+ scalar_from_field_descriptor field_descriptor
351
462
  end
352
463
  end
353
464
  define_method("#{field_name}=") do |value|
@@ -357,14 +468,16 @@ module Google
357
468
  clear_internal(field_descriptor)
358
469
  end
359
470
  if field_descriptor.type == :enum
360
- define_method("#{field_name}_const") do
361
- if field_descriptor.repeated?
471
+ if field_descriptor.repeated?
472
+ define_method("#{field_name}_const") do
362
473
  return_value = []
363
- 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|
364
475
  return_value << msg_val[:int32_val]
365
476
  end
366
477
  return_value
367
- else
478
+ end
479
+ else
480
+ define_method("#{field_name}_const") do
368
481
  message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor
369
482
  message_value[:int32_val]
370
483
  end
@@ -391,12 +504,21 @@ module Google
391
504
  end
392
505
  end
393
506
 
507
+ ##
508
+ # Dynamically define accessors methods for every OneOf field of
509
+ # @descriptor.
394
510
  def self.setup_oneof_accessors!
395
511
  @oneof_field_names = []
396
512
  @descriptor.each_oneof do |oneof_descriptor|
397
513
  self.add_oneof_accessors_for! oneof_descriptor
398
514
  end
399
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.
400
522
  def self.add_oneof_accessors_for!(oneof_descriptor)
401
523
  field_name = oneof_descriptor.name.to_sym
402
524
  @oneof_field_names << field_name
@@ -527,6 +649,10 @@ module Google
527
649
  Google::Protobuf::FFI.clear_message_field(@msg, field_def)
528
650
  end
529
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.
530
656
  def index_internal(name)
531
657
  field_descriptor = self.class.descriptor.lookup(name)
532
658
  get_field field_descriptor unless field_descriptor.nil?
@@ -554,7 +680,7 @@ module Google
554
680
  # one if omitted or nil.
555
681
  def initialize(initial_value = nil, arena = nil, msg = nil)
556
682
  @arena = arena || Google::Protobuf::FFI.create_arena
557
- @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)
558
684
 
559
685
  unless initial_value.nil?
560
686
  raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each
@@ -575,9 +701,9 @@ module Google
575
701
 
576
702
  next if value.nil?
577
703
  if field_descriptor.map?
578
- 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)
579
705
  elsif field_descriptor.repeated?
580
- 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)
581
707
  else
582
708
  index_assign_internal(value, name: key.to_s)
583
709
  end
@@ -590,21 +716,20 @@ module Google
590
716
  end
591
717
 
592
718
  ##
593
- # Gets a field of this message identified by the argument definition.
719
+ # Gets a field of this message identified by FieldDescriptor.
594
720
  #
595
- # @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.
596
723
  def get_field(field, unwrap: false)
597
724
  if field.map?
598
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
599
- get_map_field(mutable_message_value[:map], field)
725
+ map_from_field_descriptor field
600
726
  elsif field.repeated?
601
- mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
602
- get_repeated_field(mutable_message_value[:array], field)
727
+ repeated_field_from_field_descriptor field
603
728
  elsif field.sub_message?
604
729
  return nil unless Google::Protobuf::FFI.get_message_has @msg, field
605
- sub_message_def = Google::Protobuf::FFI.get_subtype_as_message(field)
606
730
  if unwrap
607
731
  if field.has?(self)
732
+ sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field
608
733
  wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field
609
734
  fields = Google::Protobuf::FFI.field_count(sub_message_def)
610
735
  raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1
@@ -615,43 +740,37 @@ module Google
615
740
  nil
616
741
  end
617
742
  else
618
- mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field, @arena
619
- sub_message = mutable_message[:msg]
620
- Descriptor.send(:get_message, sub_message, sub_message_def, @arena)
743
+ message_from_field_descriptor field
621
744
  end
622
745
  else
623
- c_type = field.send(:c_type)
624
- message_value = Google::Protobuf::FFI.get_message_value @msg, field
625
- if c_type == :enum
626
- convert_upb_to_ruby message_value, c_type, Google::Protobuf::FFI.get_subtype_as_enum(field)
627
- else
628
- convert_upb_to_ruby message_value, c_type
629
- end
746
+ scalar_from_field_descriptor field
630
747
  end
631
748
  end
632
749
 
633
750
  ##
634
- # @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
635
753
  # @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field
636
754
  def get_repeated_field(array, field)
637
755
  return nil if array.nil? or array.null?
638
756
  repeated_field = OBJECT_CACHE.get(array.address)
639
757
  if repeated_field.nil?
640
- repeated_field = RepeatedField.send(:construct_for_field, field, @arena, array: array)
641
- repeated_field.send :internal_deep_freeze if frozen?
758
+ repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array)
759
+ repeated_field.freeze if frozen?
642
760
  end
643
761
  repeated_field
644
762
  end
645
763
 
646
764
  ##
647
- # @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
648
767
  # @param field [Google::Protobuf::FieldDescriptor] Type of the map field
649
768
  def get_map_field(map, field)
650
769
  return nil if map.nil? or map.null?
651
770
  map_field = OBJECT_CACHE.get(map.address)
652
771
  if map_field.nil?
653
- map_field = Google::Protobuf::Map.send(:construct_for_field, field, @arena, map: map)
654
- map_field.send :internal_deep_freeze if frozen?
772
+ map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map)
773
+ map_field.freeze if frozen?
655
774
  end
656
775
  map_field
657
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
@@ -58,7 +58,9 @@ module Google
58
58
  size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
59
59
  temporary_arena = Google::Protobuf::FFI.create_arena
60
60
  buffer = Google::Protobuf::FFI.oneof_options(self, size_ptr, temporary_arena)
61
- Google::Protobuf::OneofOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).send(:internal_deep_freeze)
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
62
64
  end
63
65
  end
64
66
 
@@ -24,12 +24,14 @@ module Google
24
24
  module Protobuf
25
25
  class FFI
26
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
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
+ attach_function :array_freeze, :upb_Array_Freeze, [:Array, MiniTable.by_ref], :void
34
+ attach_function :array_frozen?, :upb_Array_IsFrozen, [:Array], :bool
33
35
  end
34
36
 
35
37
  class RepeatedField
@@ -174,6 +176,38 @@ module Google
174
176
  end
175
177
  alias size :length
176
178
 
179
+ ##
180
+ # Is this object frozen?
181
+ # Returns true if either this Ruby wrapper or the underlying
182
+ # representation are frozen. Freezes the wrapper if the underlying
183
+ # representation is already frozen but this wrapper isn't.
184
+ def frozen?
185
+ unless Google::Protobuf::FFI.array_frozen? array
186
+ raise RuntimeError.new "Ruby frozen RepeatedField with mutable representation" if super
187
+ return false
188
+ end
189
+ method(:freeze).super_method.call unless super
190
+ true
191
+ end
192
+
193
+ ##
194
+ # Freezes the RepeatedField object. We have to intercept this so we can
195
+ # freeze the underlying representation, not just the Ruby wrapper. Returns
196
+ # self.
197
+ def freeze
198
+ if method(:frozen?).super_method.call
199
+ unless Google::Protobuf::FFI.array_frozen? array
200
+ raise RuntimeError.new "Underlying representation of repeated field still mutable despite frozen wrapper"
201
+ end
202
+ return self
203
+ end
204
+ unless Google::Protobuf::FFI.array_frozen? array
205
+ mini_table = (type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil
206
+ Google::Protobuf::FFI.array_freeze(array, mini_table)
207
+ end
208
+ super
209
+ end
210
+
177
211
  def dup
178
212
  instance = self.class.allocate
179
213
  instance.send(:initialize, type, descriptor: descriptor, arena: arena)
@@ -252,16 +286,6 @@ module Google
252
286
 
253
287
  attr :name, :arena, :array, :type, :descriptor
254
288
 
255
- def internal_deep_freeze
256
- freeze
257
- if type == :message
258
- each do |element|
259
- element.send :internal_deep_freeze
260
- end
261
- end
262
- self
263
- end
264
-
265
289
  def internal_push(*elements)
266
290
  elements.each do |element|
267
291
  append_msg_val convert_ruby_to_upb(element, arena, type, descriptor)
@@ -346,10 +370,14 @@ module Google
346
370
  OBJECT_CACHE.try_add(@array.address, self)
347
371
  end
348
372
 
349
- # @param field [FieldDescriptor] Descriptor of the field where the RepeatedField will be assigned
350
- # @param values [Enumerable] Initial values; may be nil or empty
373
+ ##
374
+ # Constructor that uses the type information from the given
375
+ # FieldDescriptor to configure the new RepeatedField instance.
376
+ # @param field [FieldDescriptor] Type information for the new RepeatedField
351
377
  # @param arena [Arena] Owning message's arena
352
- def self.construct_for_field(field, arena, values: nil, array: nil)
378
+ # @param values [Enumerable] Initial values
379
+ # @param array [::FFI::Pointer] Existing upb_Array
380
+ def self.construct_for_field(field, arena: nil, values: nil, array: nil)
353
381
  instance = allocate
354
382
  options = {initial_values: values, name: field.name, arena: arena, array: array}
355
383
  if [:enum, :message].include? field.type