google-protobuf 3.22.5 → 3.25.5

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +23 -70
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +175 -52
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +2 -1
  8. data/ext/google/protobuf_c/glue.c +56 -0
  9. data/ext/google/protobuf_c/map.c +27 -28
  10. data/ext/google/protobuf_c/map.h +6 -28
  11. data/ext/google/protobuf_c/message.c +83 -83
  12. data/ext/google/protobuf_c/message.h +10 -28
  13. data/ext/google/protobuf_c/protobuf.c +39 -176
  14. data/ext/google/protobuf_c/protobuf.h +24 -32
  15. data/ext/google/protobuf_c/repeated_field.c +28 -29
  16. data/ext/google/protobuf_c/repeated_field.h +6 -28
  17. data/ext/google/protobuf_c/ruby-upb.c +2982 -2494
  18. data/ext/google/protobuf_c/ruby-upb.h +5838 -3467
  19. data/ext/google/protobuf_c/shared_convert.c +64 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +65 -0
  22. data/ext/google/protobuf_c/shared_message.h +25 -0
  23. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  24. data/lib/google/protobuf/any_pb.rb +24 -5
  25. data/lib/google/protobuf/api_pb.rb +26 -23
  26. data/lib/google/protobuf/descriptor_pb.rb +40 -252
  27. data/lib/google/protobuf/duration_pb.rb +24 -5
  28. data/lib/google/protobuf/empty_pb.rb +24 -3
  29. data/lib/google/protobuf/ffi/descriptor.rb +165 -0
  30. data/lib/google/protobuf/ffi/descriptor_pool.rb +75 -0
  31. data/lib/google/protobuf/ffi/enum_descriptor.rb +171 -0
  32. data/lib/google/protobuf/ffi/ffi.rb +213 -0
  33. data/lib/google/protobuf/ffi/field_descriptor.rb +319 -0
  34. data/lib/google/protobuf/ffi/file_descriptor.rb +59 -0
  35. data/lib/google/protobuf/ffi/internal/arena.rb +66 -0
  36. data/lib/google/protobuf/ffi/internal/convert.rb +305 -0
  37. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  38. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  39. data/lib/google/protobuf/ffi/map.rb +407 -0
  40. data/lib/google/protobuf/ffi/message.rb +662 -0
  41. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  42. data/lib/google/protobuf/ffi/oneof_descriptor.rb +95 -0
  43. data/lib/google/protobuf/ffi/repeated_field.rb +383 -0
  44. data/lib/google/protobuf/field_mask_pb.rb +24 -4
  45. data/lib/google/protobuf/message_exts.rb +3 -26
  46. data/lib/google/protobuf/object_cache.rb +97 -0
  47. data/lib/google/protobuf/plugin_pb.rb +25 -28
  48. data/lib/google/protobuf/repeated_field.rb +3 -26
  49. data/lib/google/protobuf/source_context_pb.rb +24 -4
  50. data/lib/google/protobuf/struct_pb.rb +24 -20
  51. data/lib/google/protobuf/timestamp_pb.rb +24 -5
  52. data/lib/google/protobuf/type_pb.rb +26 -68
  53. data/lib/google/protobuf/well_known_types.rb +5 -34
  54. data/lib/google/protobuf/wrappers_pb.rb +24 -28
  55. data/lib/google/protobuf.rb +27 -45
  56. data/lib/google/protobuf_ffi.rb +50 -0
  57. data/lib/google/protobuf_native.rb +20 -0
  58. data/lib/google/tasks/ffi.rake +102 -0
  59. metadata +72 -4
@@ -0,0 +1,171 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2022 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ class EnumDescriptor
11
+ attr :descriptor_pool, :enum_def
12
+ include Enumerable
13
+
14
+ # FFI Interface methods and setup
15
+ extend ::FFI::DataConverter
16
+ native_type ::FFI::Type::POINTER
17
+
18
+ class << self
19
+ prepend Google::Protobuf::Internal::TypeSafety
20
+ include Google::Protobuf::Internal::PointerHelper
21
+
22
+ # @param value [EnumDescriptor] EnumDescriptor to convert to an FFI native type
23
+ # @param _ [Object] Unused
24
+ def to_native(value, _)
25
+ value.instance_variable_get(:@enum_def) || ::FFI::Pointer::NULL
26
+ end
27
+
28
+ ##
29
+ # @param enum_def [::FFI::Pointer] EnumDef pointer to be wrapped
30
+ # @param _ [Object] Unused
31
+ def from_native(enum_def, _)
32
+ return nil if enum_def.nil? or enum_def.null?
33
+ file_def = Google::Protobuf::FFI.get_message_file_def enum_def
34
+ descriptor_from_file_def(file_def, enum_def)
35
+ end
36
+ end
37
+
38
+ def self.new(*arguments, &block)
39
+ raise "Descriptor objects may not be created from Ruby."
40
+ end
41
+
42
+ def file_descriptor
43
+ @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.get_enum_file_descriptor(self))
44
+ end
45
+
46
+ def name
47
+ Google::Protobuf::FFI.get_enum_fullname(self)
48
+ end
49
+
50
+ def to_s
51
+ inspect
52
+ end
53
+
54
+ def inspect
55
+ "#{self.class.name}: #{name}"
56
+ end
57
+
58
+ def lookup_name(name)
59
+ self.class.send(:lookup_name, self, name)
60
+ end
61
+
62
+ def lookup_value(number)
63
+ self.class.send(:lookup_value, self, number)
64
+ end
65
+
66
+ def each &block
67
+ n = Google::Protobuf::FFI.enum_value_count(self)
68
+ 0.upto(n - 1) do |i|
69
+ enum_value = Google::Protobuf::FFI.enum_value_by_index(self, i)
70
+ yield(Google::Protobuf::FFI.enum_name(enum_value).to_sym, Google::Protobuf::FFI.enum_number(enum_value))
71
+ end
72
+ nil
73
+ end
74
+
75
+ def enummodule
76
+ if @module.nil?
77
+ @module = build_enum_module
78
+ end
79
+ @module
80
+ end
81
+
82
+ def options
83
+ @options ||= begin
84
+ size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
85
+ temporary_arena = Google::Protobuf::FFI.create_arena
86
+ buffer = Google::Protobuf::FFI.enum_options(self, size_ptr, temporary_arena)
87
+ Google::Protobuf::EnumOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).send(:internal_deep_freeze)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def initialize(enum_def, descriptor_pool)
94
+ @descriptor_pool = descriptor_pool
95
+ @enum_def = enum_def
96
+ @module = nil
97
+ end
98
+
99
+ def self.private_constructor(enum_def, descriptor_pool)
100
+ instance = allocate
101
+ instance.send(:initialize, enum_def, descriptor_pool)
102
+ instance
103
+ end
104
+
105
+ def self.lookup_value(enum_def, number)
106
+ enum_value = Google::Protobuf::FFI.enum_value_by_number(enum_def, number)
107
+ if enum_value.null?
108
+ nil
109
+ else
110
+ Google::Protobuf::FFI.enum_name(enum_value).to_sym
111
+ end
112
+ end
113
+
114
+ def self.lookup_name(enum_def, name)
115
+ enum_value = Google::Protobuf::FFI.enum_value_by_name(enum_def, name.to_s, name.size)
116
+ if enum_value.null?
117
+ nil
118
+ else
119
+ Google::Protobuf::FFI.enum_number(enum_value)
120
+ end
121
+ end
122
+
123
+ def build_enum_module
124
+ descriptor = self
125
+ dynamic_module = Module.new do
126
+ @descriptor = descriptor
127
+
128
+ class << self
129
+ attr_accessor :descriptor
130
+ end
131
+
132
+ def self.lookup(number)
133
+ descriptor.lookup_value number
134
+ end
135
+
136
+ def self.resolve(name)
137
+ descriptor.lookup_name name
138
+ end
139
+ end
140
+
141
+ self.each do |name, value|
142
+ if name[0] < 'A' || name[0] > 'Z'
143
+ if name[0] >= 'a' and name[0] <= 'z'
144
+ name = name[0].upcase + name[1..-1] # auto capitalize
145
+ else
146
+ warn(
147
+ "Enum value '#{name}' does not start with an uppercase letter " +
148
+ "as is required for Ruby constants.")
149
+ next
150
+ end
151
+ end
152
+ dynamic_module.const_set(name.to_sym, value)
153
+ end
154
+ dynamic_module
155
+ end
156
+ end
157
+
158
+ class FFI
159
+ # EnumDescriptor
160
+ attach_function :get_enum_file_descriptor, :upb_EnumDef_File, [EnumDescriptor], :FileDef
161
+ attach_function :enum_value_by_name, :upb_EnumDef_FindValueByNameWithSize,[EnumDescriptor, :string, :size_t], :EnumValueDef
162
+ attach_function :enum_value_by_number, :upb_EnumDef_FindValueByNumber, [EnumDescriptor, :int], :EnumValueDef
163
+ attach_function :get_enum_fullname, :upb_EnumDef_FullName, [EnumDescriptor], :string
164
+ attach_function :enum_options, :EnumDescriptor_serialized_options, [EnumDescriptor, :pointer, Internal::Arena], :pointer
165
+ attach_function :enum_value_by_index, :upb_EnumDef_Value, [EnumDescriptor, :int], :EnumValueDef
166
+ attach_function :enum_value_count, :upb_EnumDef_ValueCount, [EnumDescriptor], :int
167
+ attach_function :enum_name, :upb_EnumValueDef_Name, [:EnumValueDef], :string
168
+ attach_function :enum_number, :upb_EnumValueDef_Number, [:EnumValueDef], :int
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,213 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2022 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ class FFI
11
+ extend ::FFI::Library
12
+ # Workaround for Bazel's use of symlinks + JRuby's __FILE__ and `caller`
13
+ # that resolves them.
14
+ if ENV['BAZEL'] == 'true'
15
+ ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi', ENV['PWD']
16
+ else
17
+ ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi'
18
+ end
19
+
20
+ ## Map
21
+ Upb_Map_Begin = -1
22
+
23
+ ## Encoding Status
24
+ Upb_Status_MaxMessage = 127
25
+ Upb_Encode_Deterministic = 1
26
+ Upb_Encode_SkipUnknown = 2
27
+
28
+ ## JSON Encoding options
29
+ # When set, emits 0/default values. TODO: proto3 only?
30
+ Upb_JsonEncode_EmitDefaults = 1
31
+ # When set, use normal (snake_case) field names instead of JSON (camelCase) names.
32
+ Upb_JsonEncode_UseProtoNames = 2
33
+ # When set, emits enums as their integer values instead of as their names.
34
+ Upb_JsonEncode_FormatEnumsAsIntegers = 4
35
+
36
+ ## JSON Decoding options
37
+ Upb_JsonDecode_IgnoreUnknown = 1
38
+
39
+ typedef :pointer, :Array
40
+ typedef :pointer, :DefPool
41
+ typedef :pointer, :EnumValueDef
42
+ typedef :pointer, :ExtensionRegistry
43
+ typedef :pointer, :FieldDefPointer
44
+ typedef :pointer, :FileDef
45
+ typedef :pointer, :FileDescriptorProto
46
+ typedef :pointer, :Map
47
+ typedef :pointer, :Message # Instances of a message
48
+ typedef :pointer, :OneofDefPointer
49
+ typedef :pointer, :binary_string
50
+ if ::FFI::Platform::ARCH == "aarch64"
51
+ typedef :u_int8_t, :uint8_t
52
+ typedef :u_int16_t, :uint16_t
53
+ typedef :u_int32_t, :uint32_t
54
+ typedef :u_int64_t, :uint64_t
55
+ end
56
+
57
+ FieldType = enum(
58
+ :double, 1,
59
+ :float,
60
+ :int64,
61
+ :uint64,
62
+ :int32,
63
+ :fixed64,
64
+ :fixed32,
65
+ :bool,
66
+ :string,
67
+ :group,
68
+ :message,
69
+ :bytes,
70
+ :uint32,
71
+ :enum,
72
+ :sfixed32,
73
+ :sfixed64,
74
+ :sint32,
75
+ :sint64
76
+ )
77
+
78
+ CType = enum(
79
+ :bool, 1,
80
+ :float,
81
+ :int32,
82
+ :uint32,
83
+ :enum,
84
+ :message,
85
+ :double,
86
+ :int64,
87
+ :uint64,
88
+ :string,
89
+ :bytes
90
+ )
91
+
92
+ Label = enum(
93
+ :optional, 1,
94
+ :required,
95
+ :repeated
96
+ )
97
+
98
+ Syntax = enum(
99
+ :Proto2, 2,
100
+ :Proto3
101
+ )
102
+
103
+ # All the different kind of well known type messages. For simplicity of check,
104
+ # number wrappers and string wrappers are grouped together. Make sure the
105
+ # order and merber of these groups are not changed.
106
+
107
+ WellKnown = enum(
108
+ :Unspecified,
109
+ :Any,
110
+ :FieldMask,
111
+ :Duration,
112
+ :Timestamp,
113
+ # number wrappers
114
+ :DoubleValue,
115
+ :FloatValue,
116
+ :Int64Value,
117
+ :UInt64Value,
118
+ :Int32Value,
119
+ :UInt32Value,
120
+ # string wrappers
121
+ :StringValue,
122
+ :BytesValue,
123
+ :BoolValue,
124
+ :Value,
125
+ :ListValue,
126
+ :Struct
127
+ )
128
+
129
+ DecodeStatus = enum(
130
+ :Ok,
131
+ :Malformed, # Wire format was corrupt
132
+ :OutOfMemory, # Arena alloc failed
133
+ :BadUtf8, # String field had bad UTF-8
134
+ :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH
135
+
136
+ # CheckRequired failed, but the parse otherwise succeeded.
137
+ :MissingRequired,
138
+ )
139
+
140
+ EncodeStatus = enum(
141
+ :Ok,
142
+ :OutOfMemory, # Arena alloc failed
143
+ :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH
144
+
145
+ # CheckRequired failed, but the parse otherwise succeeded.
146
+ :MissingRequired,
147
+ )
148
+
149
+ class StringView < ::FFI::Struct
150
+ layout :data, :pointer,
151
+ :size, :size_t
152
+ end
153
+
154
+ class MiniTable < ::FFI::Struct
155
+ layout :subs, :pointer,
156
+ :fields, :pointer,
157
+ :size, :uint16_t,
158
+ :field_count, :uint16_t,
159
+ :ext, :uint8_t, # upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
160
+ :dense_below, :uint8_t,
161
+ :table_mask, :uint8_t,
162
+ :required_count, :uint8_t # Required fields have the lowest hasbits.
163
+ # To statically initialize the tables of variable length, we need a flexible
164
+ # array member, and we need to compile in gnu99 mode (constant initialization
165
+ # of flexible array members is a GNU extension, not in C99 unfortunately. */
166
+ # _upb_FastTable_Entry fasttable[];
167
+ end
168
+
169
+ class Status < ::FFI::Struct
170
+ layout :ok, :bool,
171
+ :msg, [:char, Upb_Status_MaxMessage]
172
+
173
+ def initialize
174
+ super
175
+ FFI.clear self
176
+ end
177
+ end
178
+
179
+ class MessageValue < ::FFI::Union
180
+ layout :bool_val, :bool,
181
+ :float_val, :float,
182
+ :double_val, :double,
183
+ :int32_val, :int32_t,
184
+ :int64_val, :int64_t,
185
+ :uint32_val, :uint32_t,
186
+ :uint64_val,:uint64_t,
187
+ :map_val, :pointer,
188
+ :msg_val, :pointer,
189
+ :array_val,:pointer,
190
+ :str_val, StringView
191
+ end
192
+
193
+ class MutableMessageValue < ::FFI::Union
194
+ layout :map, :Map,
195
+ :msg, :Message,
196
+ :array, :Array
197
+ end
198
+
199
+ # Status
200
+ attach_function :clear, :upb_Status_Clear, [Status.by_ref], :void
201
+ attach_function :error_message, :upb_Status_ErrorMessage, [Status.by_ref], :string
202
+
203
+ # Generic
204
+ attach_function :memcmp, [:pointer, :pointer, :size_t], :int
205
+ attach_function :memcpy, [:pointer, :pointer, :size_t], :int
206
+
207
+ # Alternatives to pre-processor macros
208
+ def self.decode_max_depth(i)
209
+ i << 16
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,319 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2022 Google Inc. All rights reserved.
3
+ #
4
+ # Use of this source code is governed by a BSD-style
5
+ # license that can be found in the LICENSE file or at
6
+ # https://developers.google.com/open-source/licenses/bsd
7
+
8
+ module Google
9
+ module Protobuf
10
+ class FieldDescriptor
11
+ attr :field_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 [FieldDescriptor] FieldDescriptor to convert to an FFI native type
24
+ # @param _ [Object] Unused
25
+ def to_native(value, _)
26
+ field_def_ptr = value.instance_variable_get(:@field_def)
27
+ warn "Underlying field_def was nil!" if field_def_ptr.nil?
28
+ raise "Underlying field_def was null!" if !field_def_ptr.nil? and field_def_ptr.null?
29
+ field_def_ptr
30
+ end
31
+
32
+ ##
33
+ # @param field_def [::FFI::Pointer] FieldDef pointer to be wrapped
34
+ # @param _ [Object] Unused
35
+ def from_native(field_def, _ = nil)
36
+ return nil if field_def.nil? or field_def.null?
37
+ file_def = Google::Protobuf::FFI.file_def_by_raw_field_def(field_def)
38
+ descriptor_from_file_def(file_def, field_def)
39
+ end
40
+ end
41
+
42
+ def self.new(*arguments, &block)
43
+ raise "Descriptor objects may not be created from Ruby."
44
+ end
45
+
46
+ def to_s
47
+ inspect
48
+ end
49
+
50
+ def inspect
51
+ "#{self.class.name}: #{name}"
52
+ end
53
+
54
+ def name
55
+ @name ||= Google::Protobuf::FFI.get_full_name(self)
56
+ end
57
+
58
+ def json_name
59
+ @json_name ||= Google::Protobuf::FFI.get_json_name(self)
60
+ end
61
+
62
+ def number
63
+ @number ||= Google::Protobuf::FFI.get_number(self)
64
+ end
65
+
66
+ def type
67
+ @type ||= Google::Protobuf::FFI.get_type(self)
68
+ end
69
+
70
+ def label
71
+ @label ||= Google::Protobuf::FFI::Label[Google::Protobuf::FFI.get_label(self)]
72
+ end
73
+
74
+ def default
75
+ return nil if Google::Protobuf::FFI.is_sub_message(self)
76
+ if Google::Protobuf::FFI.is_repeated(self)
77
+ message_value = Google::Protobuf::FFI::MessageValue.new
78
+ else
79
+ message_value = Google::Protobuf::FFI.get_default(self)
80
+ end
81
+ enum_def = Google::Protobuf::FFI.get_subtype_as_enum(self)
82
+ if enum_def.null?
83
+ convert_upb_to_ruby message_value, c_type
84
+ else
85
+ convert_upb_to_ruby message_value, c_type, enum_def
86
+ end
87
+ end
88
+
89
+ def submsg_name
90
+ if defined? @submsg_name
91
+ @submsg_name
92
+ else
93
+ @submsg_name = case c_type
94
+ when :enum
95
+ Google::Protobuf::FFI.get_enum_fullname Google::Protobuf::FFI.get_subtype_as_enum self
96
+ when :message
97
+ Google::Protobuf::FFI.get_message_fullname Google::Protobuf::FFI.get_subtype_as_message self
98
+ else
99
+ nil
100
+ end
101
+ end
102
+ end
103
+
104
+ ##
105
+ # Tests if this field has been set on the argument message.
106
+ #
107
+ # @param msg [Google::Protobuf::Message]
108
+ # @return [Object] Value of the field on this message.
109
+ # @raise [TypeError] If the field is not defined on this message.
110
+ def get(msg)
111
+ if msg.class.descriptor == Google::Protobuf::FFI.get_containing_message_def(self)
112
+ msg.send :get_field, self
113
+ else
114
+ raise TypeError.new "get method called on wrong message type"
115
+ end
116
+ end
117
+
118
+ def subtype
119
+ if defined? @subtype
120
+ @subtype
121
+ else
122
+ @subtype = case c_type
123
+ when :enum
124
+ Google::Protobuf::FFI.get_subtype_as_enum(self)
125
+ when :message
126
+ Google::Protobuf::FFI.get_subtype_as_message(self)
127
+ else
128
+ nil
129
+ end
130
+ end
131
+ end
132
+
133
+ ##
134
+ # Tests if this field has been set on the argument message.
135
+ #
136
+ # @param msg [Google::Protobuf::Message]
137
+ # @return [Boolean] True iff message has this field set
138
+ # @raise [TypeError] If this field does not exist on the message
139
+ # @raise [ArgumentError] If this field does not track presence
140
+ def has?(msg)
141
+ if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self)
142
+ raise TypeError.new "has method called on wrong message type"
143
+ end
144
+ unless has_presence?
145
+ raise ArgumentError.new "does not track presence"
146
+ end
147
+
148
+ Google::Protobuf::FFI.get_message_has msg.instance_variable_get(:@msg), self
149
+ end
150
+
151
+ ##
152
+ # Tests if this field tracks presence.
153
+ #
154
+ # @return [Boolean] True iff this field tracks presence
155
+ def has_presence?
156
+ @has_presence ||= Google::Protobuf::FFI.get_has_presence(self)
157
+ end
158
+
159
+ # @param msg [Google::Protobuf::Message]
160
+ def clear(msg)
161
+ if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self)
162
+ raise TypeError.new "clear method called on wrong message type"
163
+ end
164
+ Google::Protobuf::FFI.clear_message_field msg.instance_variable_get(:@msg), self
165
+ nil
166
+ end
167
+
168
+ ##
169
+ # call-seq:
170
+ # FieldDescriptor.set(message, value)
171
+ #
172
+ # Sets the value corresponding to this field to the given value on the given
173
+ # message. Raises an exception if message is of the wrong type. Performs the
174
+ # ordinary type-checks for field setting.
175
+ #
176
+ # @param msg [Google::Protobuf::Message]
177
+ # @param value [Object]
178
+ def set(msg, value)
179
+ if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self)
180
+ raise TypeError.new "set method called on wrong message type"
181
+ end
182
+ unless set_value_on_message value, msg.instance_variable_get(:@msg), msg.instance_variable_get(:@arena)
183
+ raise RuntimeError.new "allocation failed"
184
+ end
185
+ nil
186
+ end
187
+
188
+ def map?
189
+ @map ||= Google::Protobuf::FFI.is_map self
190
+ end
191
+
192
+ def repeated?
193
+ @repeated ||= Google::Protobuf::FFI.is_repeated self
194
+ end
195
+
196
+ def sub_message?
197
+ @sub_message ||= Google::Protobuf::FFI.is_sub_message self
198
+ end
199
+
200
+ def wrapper?
201
+ if defined? @wrapper
202
+ @wrapper
203
+ else
204
+ message_descriptor = Google::Protobuf::FFI.get_subtype_as_message(self)
205
+ @wrapper = message_descriptor.nil? ? false : message_descriptor.send(:wrapper?)
206
+ end
207
+ end
208
+
209
+ def options
210
+ @options ||= begin
211
+ size_ptr = ::FFI::MemoryPointer.new(:size_t, 1)
212
+ temporary_arena = Google::Protobuf::FFI.create_arena
213
+ buffer = Google::Protobuf::FFI.field_options(self, size_ptr, temporary_arena)
214
+ Google::Protobuf::FieldOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).send(:internal_deep_freeze)
215
+ end
216
+ end
217
+
218
+ private
219
+
220
+ def initialize(field_def, descriptor_pool)
221
+ @field_def = field_def
222
+ @descriptor_pool = descriptor_pool
223
+ end
224
+
225
+ def self.private_constructor(field_def, descriptor_pool)
226
+ instance = allocate
227
+ instance.send(:initialize, field_def, descriptor_pool)
228
+ instance
229
+ end
230
+
231
+ # TODO Can this be added to the public API?
232
+ def real_containing_oneof
233
+ @real_containing_oneof ||= Google::Protobuf::FFI.real_containing_oneof self
234
+ end
235
+
236
+ # Implementation details below are subject to breaking changes without
237
+ # warning and are intended for use only within the gem.
238
+
239
+ ##
240
+ # Sets the field this FieldDescriptor represents to the given value on the given message.
241
+ # @param value [Object] Value to be set
242
+ # @param msg [::FFI::Pointer] Pointer the the upb_Message
243
+ # @param arena [Arena] Arena of the message that owns msg
244
+ def set_value_on_message(value, msg, arena, wrap: false)
245
+ message_to_alter = msg
246
+ field_def_to_set = self
247
+ if map?
248
+ raise TypeError.new "Expected map" unless value.is_a? Google::Protobuf::Map
249
+ message_descriptor = subtype
250
+
251
+ key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1)
252
+ key_field_type = Google::Protobuf::FFI.get_type(key_field_def)
253
+ raise TypeError.new "Map key type does not match field's key type" unless key_field_type == value.send(:key_type)
254
+
255
+ value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2)
256
+ value_field_type = Google::Protobuf::FFI.get_type(value_field_def)
257
+ raise TypeError.new "Map value type does not match field's value type" unless value_field_type == value.send(:value_type)
258
+
259
+ raise TypeError.new "Map value type has wrong message/enum class" unless value_field_def.subtype == value.send(:descriptor)
260
+
261
+ arena.fuse(value.send(:arena))
262
+ message_value = Google::Protobuf::FFI::MessageValue.new
263
+ message_value[:map_val] = value.send(:map_ptr)
264
+ elsif repeated?
265
+ raise TypeError.new "Expected repeated field array" unless value.is_a? RepeatedField
266
+ raise TypeError.new "Repeated field array has wrong message/enum class" unless value.send(:type) == type
267
+ arena.fuse(value.send(:arena))
268
+ message_value = Google::Protobuf::FFI::MessageValue.new
269
+ message_value[:array_val] = value.send(:array)
270
+ else
271
+ if value.nil? and (sub_message? or !real_containing_oneof.nil?)
272
+ Google::Protobuf::FFI.clear_message_field message_to_alter, field_def_to_set
273
+ return true
274
+ end
275
+ if wrap
276
+ value_field_def = Google::Protobuf::FFI.get_field_by_number subtype, 1
277
+ type_for_conversion = Google::Protobuf::FFI.get_c_type(value_field_def)
278
+ raise RuntimeError.new "Not expecting to get a msg or enum when unwrapping" if [:enum, :message].include? type_for_conversion
279
+ message_value = convert_ruby_to_upb(value, arena, type_for_conversion, nil)
280
+ message_to_alter = Google::Protobuf::FFI.get_mutable_message(msg, self, arena)[:msg]
281
+ field_def_to_set = value_field_def
282
+ else
283
+ message_value = convert_ruby_to_upb(value, arena, c_type, subtype)
284
+ end
285
+ end
286
+ Google::Protobuf::FFI.set_message_field message_to_alter, field_def_to_set, message_value, arena
287
+ end
288
+
289
+ def c_type
290
+ @c_type ||= Google::Protobuf::FFI.get_c_type(self)
291
+ end
292
+ end
293
+
294
+ class FFI
295
+ # MessageDef
296
+ attach_function :get_field_by_index, :upb_MessageDef_Field, [Descriptor, :int], FieldDescriptor
297
+ attach_function :get_field_by_name, :upb_MessageDef_FindFieldByNameWithSize,[Descriptor, :string, :size_t], FieldDescriptor
298
+ attach_function :get_field_by_number, :upb_MessageDef_FindFieldByNumber, [Descriptor, :uint32_t], FieldDescriptor
299
+
300
+ # FieldDescriptor
301
+ attach_function :field_options, :FieldDescriptor_serialized_options, [FieldDescriptor, :pointer, Internal::Arena], :pointer
302
+ attach_function :get_containing_message_def, :upb_FieldDef_ContainingType, [FieldDescriptor], Descriptor
303
+ attach_function :get_c_type, :upb_FieldDef_CType, [FieldDescriptor], CType
304
+ attach_function :get_default, :upb_FieldDef_Default, [FieldDescriptor], MessageValue.by_value
305
+ attach_function :get_subtype_as_enum, :upb_FieldDef_EnumSubDef, [FieldDescriptor], EnumDescriptor
306
+ attach_function :get_has_presence, :upb_FieldDef_HasPresence, [FieldDescriptor], :bool
307
+ attach_function :is_map, :upb_FieldDef_IsMap, [FieldDescriptor], :bool
308
+ attach_function :is_repeated, :upb_FieldDef_IsRepeated, [FieldDescriptor], :bool
309
+ attach_function :is_sub_message, :upb_FieldDef_IsSubMessage, [FieldDescriptor], :bool
310
+ attach_function :get_json_name, :upb_FieldDef_JsonName, [FieldDescriptor], :string
311
+ attach_function :get_label, :upb_FieldDef_Label, [FieldDescriptor], Label
312
+ attach_function :get_subtype_as_message, :upb_FieldDef_MessageSubDef, [FieldDescriptor], Descriptor
313
+ attach_function :get_full_name, :upb_FieldDef_Name, [FieldDescriptor], :string
314
+ attach_function :get_number, :upb_FieldDef_Number, [FieldDescriptor], :uint32_t
315
+ attach_function :get_type, :upb_FieldDef_Type, [FieldDescriptor], FieldType
316
+ attach_function :file_def_by_raw_field_def, :upb_FieldDef_File, [:pointer], :FileDef
317
+ end
318
+ end
319
+ end