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
@@ -1,465 +0,0 @@
1
- #!/usr/bin/ruby
2
- #
3
- # Code that implements the DSL for defining proto messages.
4
-
5
- # Suppress warning: loading in progress, circular require considered harmful.
6
- # This circular require is intentional to avoid missing dependency.
7
- begin
8
- old_verbose, $VERBOSE = $VERBOSE, nil
9
- require 'google/protobuf/descriptor_pb'
10
- ensure
11
- $VERBOSE = old_verbose
12
- end
13
-
14
- module Google
15
- module Protobuf
16
- module Internal
17
- class AtomicCounter
18
- def initialize
19
- @n = 0
20
- @mu = Mutex.new
21
- end
22
-
23
- def get_and_increment
24
- n = @n
25
- @mu.synchronize {
26
- @n += 1
27
- }
28
- return n
29
- end
30
- end
31
-
32
- class Builder
33
- @@file_number = AtomicCounter.new
34
-
35
- def initialize(pool)
36
- @pool = pool
37
- @default_file = nil # Constructed lazily
38
- end
39
-
40
- def add_file(name, options={}, &block)
41
- builder = FileBuilder.new(@pool, name, options)
42
- builder.instance_eval(&block)
43
- internal_add_file(builder)
44
- end
45
-
46
- def add_message(name, &block)
47
- internal_default_file.add_message(name, &block)
48
- end
49
-
50
- def add_enum(name, &block)
51
- internal_default_file.add_enum(name, &block)
52
- end
53
-
54
- # ---- Internal methods, not part of the DSL ----
55
-
56
- def build
57
- if @default_file
58
- internal_add_file(@default_file)
59
- end
60
- end
61
-
62
- private def internal_add_file(file_builder)
63
- proto = file_builder.build
64
- serialized = Google::Protobuf::FileDescriptorProto.encode(proto)
65
- @pool.add_serialized_file(serialized)
66
- end
67
-
68
- private def internal_default_file
69
- number = @@file_number.get_and_increment
70
- filename = "ruby_default_file#{number}.proto"
71
- @default_file ||= FileBuilder.new(@pool, filename)
72
- end
73
- end
74
-
75
- class FileBuilder
76
- def initialize(pool, name, options={})
77
- @pool = pool
78
- @file_proto = Google::Protobuf::FileDescriptorProto.new(
79
- name: name,
80
- syntax: options.fetch(:syntax, "proto3")
81
- )
82
- end
83
-
84
- def add_message(name, &block)
85
- builder = MessageBuilder.new(name, self, @file_proto)
86
- builder.instance_eval(&block)
87
- builder.internal_add_synthetic_oneofs
88
- end
89
-
90
- def add_enum(name, &block)
91
- EnumBuilder.new(name, @file_proto).instance_eval(&block)
92
- end
93
-
94
- # ---- Internal methods, not part of the DSL ----
95
-
96
- # These methods fix up the file descriptor to account for differences
97
- # between the DSL and FileDescriptorProto.
98
-
99
- # The DSL can omit a package name; here we infer what the package is if
100
- # was not specified.
101
- def infer_package(names)
102
- # Package is longest common prefix ending in '.', if any.
103
- if not names.empty?
104
- min, max = names.minmax
105
- last_common_dot = nil
106
- min.size.times { |i|
107
- if min[i] != max[i] then break end
108
- if min[i] == "." then last_common_dot = i end
109
- }
110
- if last_common_dot
111
- return min.slice(0, last_common_dot)
112
- end
113
- end
114
-
115
- nil
116
- end
117
-
118
- def rewrite_enum_default(field)
119
- if field.type != :TYPE_ENUM or !field.has_default_value? or !field.has_type_name?
120
- return
121
- end
122
-
123
- value = field.default_value
124
- type_name = field.type_name
125
-
126
- if value.empty? or value[0].ord < "0".ord or value[0].ord > "9".ord
127
- return
128
- end
129
-
130
- if type_name.empty? || type_name[0] != "."
131
- return
132
- end
133
-
134
- type_name = type_name[1..-1]
135
- as_int = Integer(value) rescue return
136
-
137
- enum_desc = @pool.lookup(type_name)
138
- if enum_desc.is_a?(Google::Protobuf::EnumDescriptor)
139
- # Enum was defined in a previous file.
140
- name = enum_desc.lookup_value(as_int)
141
- if name
142
- # Update the default value in the proto.
143
- field.default_value = name
144
- end
145
- else
146
- # See if enum was defined in this file.
147
- @file_proto.enum_type.each { |enum_proto|
148
- if enum_proto.name == type_name
149
- enum_proto.value.each { |enum_value_proto|
150
- if enum_value_proto.number == as_int
151
- # Update the default value in the proto.
152
- field.default_value = enum_value_proto.name
153
- return
154
- end
155
- }
156
- # We found the right enum, but no value matched.
157
- return
158
- end
159
- }
160
- end
161
- end
162
-
163
- # Historically we allowed enum defaults to be specified as a number.
164
- # In retrospect this was a mistake as descriptors require defaults to
165
- # be specified as a label. This can make a difference if multiple
166
- # labels have the same number.
167
- #
168
- # Here we do a pass over all enum defaults and rewrite numeric defaults
169
- # by looking up their labels. This is complicated by the fact that the
170
- # enum definition can live in either the symtab or the file_proto.
171
- #
172
- # We take advantage of the fact that this is called *before* enums or
173
- # messages are nested in other messages, so we only have to iterate
174
- # one level deep.
175
- def rewrite_enum_defaults
176
- @file_proto.message_type.each { |msg|
177
- msg.field.each { |field|
178
- rewrite_enum_default(field)
179
- }
180
- }
181
- end
182
-
183
- # We have to do some relatively complicated logic here for backward
184
- # compatibility.
185
- #
186
- # In descriptor.proto, messages are nested inside other messages if that is
187
- # what the original .proto file looks like. For example, suppose we have this
188
- # foo.proto:
189
- #
190
- # package foo;
191
- # message Bar {
192
- # message Baz {}
193
- # }
194
- #
195
- # The descriptor for this must look like this:
196
- #
197
- # file {
198
- # name: "test.proto"
199
- # package: "foo"
200
- # message_type {
201
- # name: "Bar"
202
- # nested_type {
203
- # name: "Baz"
204
- # }
205
- # }
206
- # }
207
- #
208
- # However, the Ruby generated code has always generated messages in a flat,
209
- # non-nested way:
210
- #
211
- # Google::Protobuf::DescriptorPool.generated_pool.build do
212
- # add_message "foo.Bar" do
213
- # end
214
- # add_message "foo.Bar.Baz" do
215
- # end
216
- # end
217
- #
218
- # Here we need to do a translation where we turn this generated code into the
219
- # above descriptor. We need to infer that "foo" is the package name, and not
220
- # a message itself. */
221
-
222
- def split_parent_name(msg_or_enum)
223
- name = msg_or_enum.name
224
- idx = name.rindex(?.)
225
- if idx
226
- return name[0...idx], name[idx+1..-1]
227
- else
228
- return nil, name
229
- end
230
- end
231
-
232
- def get_parent_msg(msgs_by_name, name, parent_name)
233
- parent_msg = msgs_by_name[parent_name]
234
- if parent_msg.nil?
235
- raise "To define name #{name}, there must be a message named #{parent_name} to enclose it"
236
- end
237
- return parent_msg
238
- end
239
-
240
- def fix_nesting
241
- # Calculate and update package.
242
- msgs_by_name = @file_proto.message_type.map { |msg| [msg.name, msg] }.to_h
243
- enum_names = @file_proto.enum_type.map { |enum_proto| enum_proto.name }
244
-
245
- package = infer_package(msgs_by_name.keys + enum_names)
246
- if package
247
- @file_proto.package = package
248
- end
249
-
250
- # Update nesting based on package.
251
- final_msgs = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::DescriptorProto)
252
- final_enums = Google::Protobuf::RepeatedField.new(:message, Google::Protobuf::EnumDescriptorProto)
253
-
254
- # Note: We don't iterate over msgs_by_name.values because we want to
255
- # preserve order as listed in the DSL.
256
- @file_proto.message_type.each { |msg|
257
- parent_name, msg.name = split_parent_name(msg)
258
- if parent_name == package
259
- final_msgs << msg
260
- else
261
- get_parent_msg(msgs_by_name, msg.name, parent_name).nested_type << msg
262
- end
263
- }
264
-
265
- @file_proto.enum_type.each { |enum|
266
- parent_name, enum.name = split_parent_name(enum)
267
- if parent_name == package
268
- final_enums << enum
269
- else
270
- get_parent_msg(msgs_by_name, enum.name, parent_name).enum_type << enum
271
- end
272
- }
273
-
274
- @file_proto.message_type = final_msgs
275
- @file_proto.enum_type = final_enums
276
- end
277
-
278
- def internal_file_proto
279
- @file_proto
280
- end
281
-
282
- def build
283
- rewrite_enum_defaults
284
- fix_nesting
285
- return @file_proto
286
- end
287
- end
288
-
289
- class MessageBuilder
290
- def initialize(name, file_builder, file_proto)
291
- @file_builder = file_builder
292
- @msg_proto = Google::Protobuf::DescriptorProto.new(
293
- :name => name
294
- )
295
- file_proto.message_type << @msg_proto
296
- end
297
-
298
- def optional(name, type, number, type_class=nil, options=nil)
299
- internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options)
300
- end
301
-
302
- def proto3_optional(name, type, number, type_class=nil, options=nil)
303
- internal_add_field(:LABEL_OPTIONAL, name, type, number, type_class, options,
304
- proto3_optional: true)
305
- end
306
-
307
- def required(name, type, number, type_class=nil, options=nil)
308
- internal_add_field(:LABEL_REQUIRED, name, type, number, type_class, options)
309
- end
310
-
311
- def repeated(name, type, number, type_class = nil, options=nil)
312
- internal_add_field(:LABEL_REPEATED, name, type, number, type_class, options)
313
- end
314
-
315
- def oneof(name, &block)
316
- OneofBuilder.new(name, self).instance_eval(&block)
317
- end
318
-
319
- # Defines a new map field on this message type with the given key and
320
- # value types, tag number, and type class (for message and enum value
321
- # types). The key type must be :int32/:uint32/:int64/:uint64, :bool, or
322
- # :string. The value type type must be a Ruby symbol (as accepted by
323
- # FieldDescriptor#type=) and the type_class must be a string, if
324
- # present (as accepted by FieldDescriptor#submsg_name=).
325
- def map(name, key_type, value_type, number, value_type_class = nil)
326
- if key_type == :float or key_type == :double or key_type == :enum or
327
- key_type == :message
328
- raise ArgError, "Not an acceptable key type: " + key_type
329
- end
330
- entry_name = "#{@msg_proto.name}_MapEntry_#{name}"
331
-
332
- @file_builder.add_message entry_name do
333
- optional :key, key_type, 1
334
- optional :value, value_type, 2, value_type_class
335
- end
336
- options = @file_builder.internal_file_proto.message_type.last.options ||= MessageOptions.new
337
- options.map_entry = true
338
- repeated name, :message, number, entry_name
339
- end
340
-
341
- # ---- Internal methods, not part of the DSL ----
342
-
343
- def internal_add_synthetic_oneofs
344
- # We have to build a set of all names, to ensure that synthetic oneofs
345
- # are not creating conflicts
346
- names = {}
347
- @msg_proto.field.each { |field| names[field.name] = true }
348
- @msg_proto.oneof_decl.each { |oneof| names[oneof.name] = true }
349
-
350
- @msg_proto.field.each { |field|
351
- if field.proto3_optional
352
- # Prepend '_' until we are no longer conflicting.
353
- oneof_name = field.name
354
- while names[oneof_name]
355
- oneof_name = "_" + oneof_name
356
- end
357
- names[oneof_name] = true
358
- field.oneof_index = @msg_proto.oneof_decl.size
359
- @msg_proto.oneof_decl << Google::Protobuf::OneofDescriptorProto.new(
360
- name: oneof_name
361
- )
362
- end
363
- }
364
- end
365
-
366
- def internal_add_field(label, name, type, number, type_class, options,
367
- oneof_index: nil, proto3_optional: false)
368
- # Allow passing either:
369
- # - (name, type, number, options) or
370
- # - (name, type, number, type_class, options)
371
- if options.nil? and type_class.instance_of?(Hash)
372
- options = type_class;
373
- type_class = nil;
374
- end
375
-
376
- field_proto = Google::Protobuf::FieldDescriptorProto.new(
377
- :label => label,
378
- :name => name,
379
- :type => ("TYPE_" + type.to_s.upcase).to_sym,
380
- :number => number
381
- )
382
-
383
- if type_class
384
- # Make it an absolute type name by prepending a dot.
385
- field_proto.type_name = "." + type_class
386
- end
387
-
388
- if oneof_index
389
- field_proto.oneof_index = oneof_index
390
- end
391
-
392
- if proto3_optional
393
- field_proto.proto3_optional = true
394
- end
395
-
396
- if options
397
- if options.key?(:default)
398
- default = options[:default]
399
- if !default.instance_of?(String)
400
- # Call #to_s since all defaults are strings in the descriptor.
401
- default = default.to_s
402
- end
403
- # XXX: we should be C-escaping bytes defaults.
404
- field_proto.default_value = default.dup.force_encoding("UTF-8")
405
- end
406
- if options.key?(:json_name)
407
- field_proto.json_name = options[:json_name]
408
- end
409
- end
410
-
411
- @msg_proto.field << field_proto
412
- end
413
-
414
- def internal_msg_proto
415
- @msg_proto
416
- end
417
- end
418
-
419
- class OneofBuilder
420
- def initialize(name, msg_builder)
421
- @msg_builder = msg_builder
422
- oneof_proto = Google::Protobuf::OneofDescriptorProto.new(
423
- :name => name
424
- )
425
- msg_proto = msg_builder.internal_msg_proto
426
- @oneof_index = msg_proto.oneof_decl.size
427
- msg_proto.oneof_decl << oneof_proto
428
- end
429
-
430
- def optional(name, type, number, type_class=nil, options=nil)
431
- @msg_builder.internal_add_field(
432
- :LABEL_OPTIONAL, name, type, number, type_class, options,
433
- oneof_index: @oneof_index)
434
- end
435
- end
436
-
437
- class EnumBuilder
438
- def initialize(name, file_proto)
439
- @enum_proto = Google::Protobuf::EnumDescriptorProto.new(
440
- :name => name
441
- )
442
- file_proto.enum_type << @enum_proto
443
- end
444
-
445
- def value(name, number)
446
- enum_value_proto = Google::Protobuf::EnumValueDescriptorProto.new(
447
- name: name,
448
- number: number
449
- )
450
- @enum_proto.value << enum_value_proto
451
- end
452
- end
453
-
454
- end
455
-
456
- # Re-open the class (the rest of the class is implemented in C)
457
- class DescriptorPool
458
- def build(&block)
459
- builder = Internal::Builder.new(self)
460
- builder.instance_eval(&block)
461
- builder.build
462
- end
463
- end
464
- end
465
- end
@@ -1,97 +0,0 @@
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
- # A pointer -> Ruby Object cache that keeps references to Ruby wrapper
11
- # objects. This allows us to look up any Ruby wrapper object by the address
12
- # of the object it is wrapping. That way we can avoid ever creating two
13
- # different wrapper objects for the same C object, which saves memory and
14
- # preserves object identity.
15
- #
16
- # We use WeakMap for the cache. If sizeof(long) > sizeof(VALUE), we also
17
- # need a secondary Hash to store WeakMap keys, because our pointer keys may
18
- # need to be stored as Bignum instead of Fixnum. Since WeakMap is weak for
19
- # both keys and values, a Bignum key will cause the WeakMap entry to be
20
- # collected immediately unless there is another reference to the Bignum.
21
- # This happens on 64-bit Windows, on which pointers are 64 bits but longs
22
- # are 32 bits. In this case, we enable the secondary Hash to hold the keys
23
- # and prevent them from being collected.
24
- class ObjectCache
25
- def initialize
26
- @map = ObjectSpace::WeakMap.new
27
- @mutex = Mutex.new
28
- end
29
-
30
- def get(key)
31
- @map[key]
32
- end
33
-
34
- def try_add(key, value)
35
- @map[key] || @mutex.synchronize do
36
- @map[key] ||= value
37
- end
38
- end
39
- end
40
-
41
- class LegacyObjectCache
42
- def initialize
43
- @secondary_map = {}
44
- @map = ObjectSpace::WeakMap.new
45
- @mutex = Mutex.new
46
- end
47
-
48
- def get(key)
49
- value = if secondary_key = @secondary_map[key]
50
- @map[secondary_key]
51
- else
52
- @mutex.synchronize do
53
- @map[(@secondary_map[key] ||= Object.new)]
54
- end
55
- end
56
-
57
- # GC if we could remove at least 2000 entries or 20% of the table size
58
- # (whichever is greater). Since the cost of the GC pass is O(N), we
59
- # want to make sure that we condition this on overall table size, to
60
- # avoid O(N^2) CPU costs.
61
- cutoff = (@secondary_map.size * 0.2).ceil
62
- cutoff = 2_000 if cutoff < 2_000
63
- if (@secondary_map.size - @map.size) > cutoff
64
- purge
65
- end
66
-
67
- value
68
- end
69
-
70
- def try_add(key, value)
71
- if secondary_key = @secondary_map[key]
72
- if old_value = @map[secondary_key]
73
- return old_value
74
- end
75
- end
76
-
77
- @mutex.synchronize do
78
- secondary_key ||= (@secondary_map[key] ||= Object.new)
79
- @map[secondary_key] ||= value
80
- end
81
- end
82
-
83
- private
84
-
85
- def purge
86
- @mutex.synchronize do
87
- @secondary_map.each do |key, secondary_key|
88
- unless @map.key?(secondary_key)
89
- @secondary_map.delete(key)
90
- end
91
- end
92
- end
93
- nil
94
- end
95
- end
96
- end
97
- end