google-protobuf 3.21.2 → 4.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/Rakefile +3 -0
  3. data/ext/google/protobuf_c/convert.c +67 -86
  4. data/ext/google/protobuf_c/convert.h +3 -28
  5. data/ext/google/protobuf_c/defs.c +538 -77
  6. data/ext/google/protobuf_c/defs.h +3 -28
  7. data/ext/google/protobuf_c/extconf.rb +4 -4
  8. data/ext/google/protobuf_c/glue.c +72 -0
  9. data/ext/google/protobuf_c/map.c +114 -85
  10. data/ext/google/protobuf_c/map.h +12 -30
  11. data/ext/google/protobuf_c/message.c +264 -238
  12. data/ext/google/protobuf_c/message.h +11 -33
  13. data/ext/google/protobuf_c/protobuf.c +63 -187
  14. data/ext/google/protobuf_c/protobuf.h +27 -39
  15. data/ext/google/protobuf_c/repeated_field.c +72 -38
  16. data/ext/google/protobuf_c/repeated_field.h +11 -29
  17. data/ext/google/protobuf_c/ruby-upb.c +13783 -8236
  18. data/ext/google/protobuf_c/ruby-upb.h +14077 -4495
  19. data/ext/google/protobuf_c/shared_convert.c +69 -0
  20. data/ext/google/protobuf_c/shared_convert.h +26 -0
  21. data/ext/google/protobuf_c/shared_message.c +37 -0
  22. data/ext/google/protobuf_c/shared_message.h +21 -0
  23. data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +1 -0
  24. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +467 -0
  25. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +20 -7
  26. data/ext/google/protobuf_c/wrap_memcpy.c +3 -26
  27. data/lib/google/protobuf/any_pb.rb +6 -8
  28. data/lib/google/protobuf/api_pb.rb +6 -26
  29. data/lib/google/protobuf/descriptor_pb.rb +23 -226
  30. data/lib/google/protobuf/duration_pb.rb +6 -8
  31. data/lib/google/protobuf/empty_pb.rb +6 -6
  32. data/lib/google/protobuf/ffi/descriptor.rb +165 -0
  33. data/lib/google/protobuf/ffi/descriptor_pool.rb +77 -0
  34. data/lib/google/protobuf/ffi/enum_descriptor.rb +173 -0
  35. data/lib/google/protobuf/ffi/ffi.rb +215 -0
  36. data/lib/google/protobuf/ffi/field_descriptor.rb +330 -0
  37. data/lib/google/protobuf/ffi/file_descriptor.rb +49 -0
  38. data/lib/google/protobuf/ffi/internal/arena.rb +60 -0
  39. data/lib/google/protobuf/ffi/internal/convert.rb +296 -0
  40. data/lib/google/protobuf/ffi/internal/pointer_helper.rb +35 -0
  41. data/lib/google/protobuf/ffi/internal/type_safety.rb +25 -0
  42. data/lib/google/protobuf/ffi/map.rb +433 -0
  43. data/lib/google/protobuf/ffi/message.rb +785 -0
  44. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  45. data/lib/google/protobuf/ffi/object_cache.rb +30 -0
  46. data/lib/google/protobuf/ffi/oneof_descriptor.rb +97 -0
  47. data/lib/google/protobuf/ffi/repeated_field.rb +411 -0
  48. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  49. data/lib/google/protobuf/field_mask_pb.rb +6 -7
  50. data/lib/google/protobuf/internal/object_cache.rb +99 -0
  51. data/lib/google/protobuf/message_exts.rb +8 -26
  52. data/lib/google/protobuf/plugin_pb.rb +25 -0
  53. data/lib/google/protobuf/repeated_field.rb +7 -31
  54. data/lib/google/protobuf/source_context_pb.rb +6 -7
  55. data/lib/google/protobuf/struct_pb.rb +6 -23
  56. data/lib/google/protobuf/timestamp_pb.rb +6 -8
  57. data/lib/google/protobuf/type_pb.rb +6 -71
  58. data/lib/google/protobuf/well_known_types.rb +5 -34
  59. data/lib/google/protobuf/wrappers_pb.rb +6 -31
  60. data/lib/google/protobuf.rb +27 -45
  61. data/lib/google/protobuf_ffi.rb +51 -0
  62. data/lib/google/protobuf_native.rb +19 -0
  63. data/lib/google/tasks/ffi.rake +100 -0
  64. metadata +92 -16
  65. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +0 -92
  66. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +0 -157
  67. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +0 -170
  68. data/lib/google/protobuf/descriptor_dsl.rb +0 -465
  69. data/tests/basic.rb +0 -739
  70. data/tests/generated_code_test.rb +0 -23
  71. data/tests/stress.rb +0 -38
@@ -0,0 +1,296 @@
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
+ ##
9
+ # Implementation details below are subject to breaking changes without
10
+ # warning and are intended for use only within the gem.
11
+ module Google
12
+ module Protobuf
13
+ module Internal
14
+ module Convert
15
+
16
+ # Arena should be the
17
+ # @param value [Object] Value to convert
18
+ # @param arena [Arena] Arena that owns the Message where the MessageValue
19
+ # will be set
20
+ # @return [Google::Protobuf::FFI::MessageValue]
21
+ def convert_ruby_to_upb(value, arena, c_type, msg_or_enum_def)
22
+ raise ArgumentError.new "Expected Descriptor or EnumDescriptor, instead got #{msg_or_enum_def.class}" unless [NilClass, Descriptor, EnumDescriptor].include? msg_or_enum_def.class
23
+ return_value = Google::Protobuf::FFI::MessageValue.new
24
+ case c_type
25
+ when :float
26
+ raise TypeError.new "Expected number type for float field '#{name}' (given #{value.class})." unless value.respond_to? :to_f
27
+ return_value[:float_val] = value.to_f
28
+ when :double
29
+ raise TypeError.new "Expected number type for double field '#{name}' (given #{value.class})." unless value.respond_to? :to_f
30
+ return_value[:double_val] = value.to_f
31
+ when :bool
32
+ raise TypeError.new "Invalid argument for boolean field '#{name}' (given #{value.class})." unless [TrueClass, FalseClass].include? value.class
33
+ return_value[:bool_val] = value
34
+ when :string
35
+ raise TypeError.new "Invalid argument for string field '#{name}' (given #{value.class})." unless value.is_a?(String) or value.is_a?(Symbol)
36
+ value = value.to_s if value.is_a?(Symbol)
37
+ if value.encoding == Encoding::UTF_8
38
+ unless value.valid_encoding?
39
+ # TODO:
40
+ # For now we only warn for this case. We will remove the
41
+ # warning and throw an exception below in the 30.x release
42
+ warn "String is invalid UTF-8. This will be an error in a future version."
43
+ # raise Encoding::InvalidByteSequenceError.new "String is invalid UTF-8"
44
+ end
45
+ string_value = value
46
+ else
47
+ string_value = value.to_s.encode("UTF-8")
48
+ end
49
+ return_value[:str_val][:size] = string_value.bytesize
50
+ return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize)
51
+ # TODO - how important is it to still use arena malloc, versus the following?
52
+ # buffer = ::FFI::MemoryPointer.new(:char, string_value.bytesize)
53
+ # buffer.put_bytes(0, string_value)
54
+ # return_value[:str_val][:data] = buffer
55
+ raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for string on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null?
56
+ return_value[:str_val][:data].write_string(string_value)
57
+ when :bytes
58
+ raise TypeError.new "Invalid argument for bytes field '#{name}' (given #{value.class})." unless value.is_a? String
59
+ string_value = value.encode("ASCII-8BIT")
60
+ return_value[:str_val][:size] = string_value.bytesize
61
+ return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize)
62
+ raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for bytes on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null?
63
+ return_value[:str_val][:data].write_string_length(string_value, string_value.bytesize)
64
+ when :message
65
+ raise TypeError.new "nil message not allowed here." if value.nil?
66
+ if value.is_a? Hash
67
+ raise RuntimeError.new "Attempted to initialize message from Hash for field #{name} but have no definition" if msg_or_enum_def.nil?
68
+ new_message = msg_or_enum_def.msgclass.
69
+ send(:private_constructor, arena, initial_value: value)
70
+ return_value[:msg_val] = new_message.instance_variable_get(:@msg)
71
+ return return_value
72
+ end
73
+
74
+ descriptor = value.class.respond_to?(:descriptor) ? value.class.descriptor : nil
75
+ if descriptor != msg_or_enum_def
76
+ wkt = Google::Protobuf::FFI.get_well_known_type(msg_or_enum_def)
77
+ case wkt
78
+ when :Timestamp
79
+ raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Time
80
+ new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena
81
+ sec = Google::Protobuf::FFI::MessageValue.new
82
+ sec[:int64_val] = value.tv_sec
83
+ sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1
84
+ raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena
85
+ nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2
86
+ nsec = Google::Protobuf::FFI::MessageValue.new
87
+ nsec[:int32_val] = value.tv_nsec
88
+ raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena
89
+ return_value[:msg_val] = new_message
90
+ when :Duration
91
+ raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Numeric
92
+ new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena
93
+ sec = Google::Protobuf::FFI::MessageValue.new
94
+ sec[:int64_val] = value
95
+ sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1
96
+ raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena
97
+ nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2
98
+ nsec = Google::Protobuf::FFI::MessageValue.new
99
+ nsec[:int32_val] = ((value.to_f - value.to_i) * 1000000000).round
100
+ raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena
101
+ return_value[:msg_val] = new_message
102
+ else
103
+ raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'."
104
+ end
105
+ else
106
+ arena.fuse(value.instance_variable_get(:@arena))
107
+ return_value[:msg_val] = value.instance_variable_get :@msg
108
+ end
109
+ when :enum
110
+ return_value[:int32_val] = case value
111
+ when Numeric
112
+ value.to_i
113
+ when String, Symbol
114
+ enum_number = EnumDescriptor.send(:lookup_name, msg_or_enum_def, value.to_s)
115
+ #TODO add the bad value to the error message after tests pass
116
+ raise RangeError.new "Unknown symbol value for enum field '#{name}'." if enum_number.nil?
117
+ enum_number
118
+ else
119
+ raise TypeError.new "Expected number or symbol type for enum field '#{name}'."
120
+ end
121
+ #TODO After all tests pass, improve error message across integer type by including actual offending value
122
+ when :int32
123
+ raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric
124
+ raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value
125
+ raise RangeError.new "Value assigned to int32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 32
126
+ return_value[:int32_val] = value.to_i
127
+ when :uint32
128
+ raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric
129
+ raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value
130
+ raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0
131
+ raise RangeError.new "Value assigned to uint32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 33
132
+ return_value[:uint32_val] = value.to_i
133
+ when :int64
134
+ raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric
135
+ raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value
136
+ raise RangeError.new "Value assigned to int64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 64
137
+ return_value[:int64_val] = value.to_i
138
+ when :uint64
139
+ raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric
140
+ raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value
141
+ raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0
142
+ raise RangeError.new "Value assigned to uint64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 65
143
+ return_value[:uint64_val] = value.to_i
144
+ else
145
+ raise RuntimeError.new "Unsupported type #{c_type}"
146
+ end
147
+ return_value
148
+ end
149
+
150
+ ##
151
+ # Safe to call without an arena if the caller has checked that c_type
152
+ # is not :message.
153
+ # @param message_value [Google::Protobuf::FFI::MessageValue] Value to be converted.
154
+ # @param c_type [Google::Protobuf::FFI::CType] Enum representing the type of message_value
155
+ # @param msg_or_enum_def [::FFI::Pointer] Pointer to the MsgDef or EnumDef definition
156
+ # @param arena [Google::Protobuf::Internal::Arena] Arena to create Message instances, if needed
157
+ def convert_upb_to_ruby(message_value, c_type, msg_or_enum_def = nil, arena = nil)
158
+ throw TypeError.new "Expected MessageValue but got #{message_value.class}" unless message_value.is_a? Google::Protobuf::FFI::MessageValue
159
+
160
+ case c_type
161
+ when :bool
162
+ message_value[:bool_val]
163
+ when :int32
164
+ message_value[:int32_val]
165
+ when :uint32
166
+ message_value[:uint32_val]
167
+ when :double
168
+ message_value[:double_val]
169
+ when :int64
170
+ message_value[:int64_val]
171
+ when :uint64
172
+ message_value[:uint64_val]
173
+ when :string
174
+ if message_value[:str_val][:size].zero?
175
+ ""
176
+ else
177
+ message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("UTF-8").freeze
178
+ end
179
+ when :bytes
180
+ if message_value[:str_val][:size].zero?
181
+ ""
182
+ else
183
+ message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("ASCII-8BIT").freeze
184
+ end
185
+ when :float
186
+ message_value[:float_val]
187
+ when :enum
188
+ EnumDescriptor.send(:lookup_value, msg_or_enum_def, message_value[:int32_val]) || message_value[:int32_val]
189
+ when :message
190
+ raise "Null Arena for message" if arena.nil?
191
+ Descriptor.send(:get_message, message_value[:msg_val], msg_or_enum_def, arena)
192
+ else
193
+ raise RuntimeError.new "Unexpected type #{c_type}"
194
+ end
195
+ end
196
+
197
+ def to_h_internal(msg, message_descriptor)
198
+ return nil if msg.nil? or msg.null?
199
+ hash = {}
200
+ iter = ::FFI::MemoryPointer.new(:size_t, 1)
201
+ iter.write(:size_t, Google::Protobuf::FFI::Upb_Message_Begin)
202
+ message_value = Google::Protobuf::FFI::MessageValue.new
203
+ field_def_ptr = ::FFI::MemoryPointer.new :pointer
204
+
205
+ while Google::Protobuf::FFI::message_next(msg, message_descriptor, nil, field_def_ptr, message_value, iter) do
206
+ field_descriptor = FieldDescriptor.from_native field_def_ptr.get_pointer(0)
207
+
208
+ if field_descriptor.map?
209
+ hash_entry = map_create_hash(message_value[:map_val], field_descriptor)
210
+ elsif field_descriptor.repeated?
211
+ hash_entry = repeated_field_create_array(message_value[:array_val], field_descriptor, field_descriptor.type)
212
+ else
213
+ hash_entry = scalar_create_hash(message_value, field_descriptor.type, field_descriptor: field_descriptor)
214
+ end
215
+
216
+ hash[field_descriptor.name.to_sym] = hash_entry
217
+ end
218
+
219
+ hash
220
+ end
221
+
222
+ def map_create_hash(map_ptr, field_descriptor)
223
+ return {} if map_ptr.nil? or map_ptr.null?
224
+ return_value = {}
225
+
226
+ message_descriptor = field_descriptor.send(:subtype)
227
+ key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1)
228
+ key_field_type = Google::Protobuf::FFI.get_type(key_field_def)
229
+
230
+ value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2)
231
+ value_field_type = Google::Protobuf::FFI.get_type(value_field_def)
232
+
233
+ iter = ::FFI::MemoryPointer.new(:size_t, 1)
234
+ iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin)
235
+ while Google::Protobuf::FFI.map_next(map_ptr, iter) do
236
+ iter_size_t = iter.read(:size_t)
237
+ key_message_value = Google::Protobuf::FFI.map_key(map_ptr, iter_size_t)
238
+ value_message_value = Google::Protobuf::FFI.map_value(map_ptr, iter_size_t)
239
+ hash_key = convert_upb_to_ruby(key_message_value, key_field_type)
240
+ hash_value = scalar_create_hash(value_message_value, value_field_type, msg_or_enum_descriptor: value_field_def.subtype)
241
+ return_value[hash_key] = hash_value
242
+ end
243
+ return_value
244
+ end
245
+
246
+ def repeated_field_create_array(array, field_descriptor, type)
247
+ return_value = []
248
+ n = (array.nil? || array.null?) ? 0 : Google::Protobuf::FFI.array_size(array)
249
+ 0.upto(n - 1) do |i|
250
+ message_value = Google::Protobuf::FFI.get_msgval_at(array, i)
251
+ return_value << scalar_create_hash(message_value, type, field_descriptor: field_descriptor)
252
+ end
253
+ return_value
254
+ end
255
+
256
+ # @param field_descriptor [FieldDescriptor] Descriptor of the field to convert to a hash.
257
+ def scalar_create_hash(message_value, type, field_descriptor: nil, msg_or_enum_descriptor: nil)
258
+ if [:message, :enum].include? type
259
+ if field_descriptor.nil?
260
+ if msg_or_enum_descriptor.nil?
261
+ raise "scalar_create_hash requires either a FieldDescriptor, MessageDescriptor, or EnumDescriptor as an argument, but received only nil"
262
+ end
263
+ else
264
+ msg_or_enum_descriptor = field_descriptor.subtype
265
+ end
266
+ if type == :message
267
+ to_h_internal(message_value[:msg_val], msg_or_enum_descriptor)
268
+ elsif type == :enum
269
+ convert_upb_to_ruby message_value, type, msg_or_enum_descriptor
270
+ end
271
+ else
272
+ convert_upb_to_ruby message_value, type
273
+ end
274
+ end
275
+
276
+ def message_value_deep_copy(message_value, type, descriptor, arena)
277
+ raise unless message_value.is_a? Google::Protobuf::FFI::MessageValue
278
+ new_message_value = Google::Protobuf::FFI::MessageValue.new
279
+ case type
280
+ when :string, :bytes
281
+ # TODO - how important is it to still use arena malloc, versus using FFI MemoryPointers?
282
+ new_message_value[:str_val][:size] = message_value[:str_val][:size]
283
+ new_message_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, message_value[:str_val][:size])
284
+ raise NoMemoryError.new "Allocation failed" if new_message_value[:str_val][:data].nil? or new_message_value[:str_val][:data].null?
285
+ Google::Protobuf::FFI.memcpy(new_message_value[:str_val][:data], message_value[:str_val][:data], message_value[:str_val][:size])
286
+ when :message
287
+ new_message_value[:msg_val] = descriptor.msgclass.send(:deep_copy, message_value[:msg_val], arena).instance_variable_get(:@msg)
288
+ else
289
+ Google::Protobuf::FFI.memcpy(new_message_value.to_ptr, message_value.to_ptr, Google::Protobuf::FFI::MessageValue.size)
290
+ end
291
+ new_message_value
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
@@ -0,0 +1,35 @@
1
+ # Protocol Buffers - Google's data interchange format
2
+ # Copyright 2023 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
+ module Internal
11
+ module PointerHelper
12
+ # Utility code to defensively walk the object graph from a file_def to
13
+ # the pool, and either retrieve the wrapper object for the given pointer
14
+ # or create one. Assumes that the caller is the wrapper class for the
15
+ # given pointer and that it implements `private_constructor`.
16
+ def descriptor_from_file_def(file_def, pointer)
17
+ raise RuntimeError.new "FileDef is nil" if file_def.nil?
18
+ raise RuntimeError.new "FileDef is null" if file_def.null?
19
+ pool_def = Google::Protobuf::FFI.file_def_pool file_def
20
+ raise RuntimeError.new "PoolDef is nil" if pool_def.nil?
21
+ raise RuntimeError.new "PoolDef is null" if pool_def.null?
22
+ pool = Google::Protobuf::OBJECT_CACHE.get(pool_def.address)
23
+ raise "Cannot find pool in ObjectCache!" if pool.nil?
24
+ descriptor = pool.descriptor_class_by_def[pointer.address]
25
+ if descriptor.nil?
26
+ pool.descriptor_class_by_def[pointer.address] = private_constructor(pointer, pool)
27
+ else
28
+ descriptor
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,25 @@
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
+ # A to_native DataConverter method that raises an error if the value is not of the same type.
9
+ # Adapted from to https://www.varvet.com/blog/advanced-topics-in-ruby-ffi/
10
+ module Google
11
+ module Protobuf
12
+ module Internal
13
+ module TypeSafety
14
+ def to_native(value, ctx = nil)
15
+ if value.kind_of?(self) or value.nil?
16
+ super
17
+ else
18
+ raise TypeError.new "Expected a kind of #{name}, was #{value.class}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+