protobuf 3.8.5 → 3.9.0.pre
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +3 -4
- data/lib/protobuf.rb +14 -0
- data/lib/protobuf/code_generator.rb +30 -3
- data/lib/protobuf/encoder.rb +1 -12
- data/lib/protobuf/enum.rb +11 -9
- data/lib/protobuf/field/base_field.rb +177 -34
- data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
- data/lib/protobuf/field/bool_field.rb +13 -8
- data/lib/protobuf/field/bytes_field.rb +8 -19
- data/lib/protobuf/field/enum_field.rb +9 -11
- data/lib/protobuf/field/int64_field.rb +13 -0
- data/lib/protobuf/field/message_field.rb +1 -1
- data/lib/protobuf/field/string_field.rb +20 -15
- data/lib/protobuf/field/varint_field.rb +13 -26
- data/lib/protobuf/message.rb +44 -99
- data/lib/protobuf/message/fields.rb +16 -0
- data/lib/protobuf/message/serialization.rb +1 -1
- data/lib/protobuf/varint.rb +11 -0
- data/lib/protobuf/varint_pure.rb +18 -0
- data/lib/protobuf/version.rb +1 -1
- data/profile.html +5103 -0
- data/protobuf.gemspec +3 -1
- data/varint_prof.rb +82 -0
- metadata +52 -151
@@ -3,10 +3,14 @@ require 'protobuf/field/varint_field'
|
|
3
3
|
module Protobuf
|
4
4
|
module Field
|
5
5
|
class BoolField < VarintField
|
6
|
+
ONE = 1
|
6
7
|
FALSE_ENCODE = [0].pack('C')
|
7
8
|
FALSE_STRING = "false".freeze
|
9
|
+
FALSE_VALUES = [false, FALSE_STRING].freeze
|
8
10
|
TRUE_ENCODE = [1].pack('C')
|
9
11
|
TRUE_STRING = "true".freeze
|
12
|
+
TRUE_VALUES = [true, TRUE_STRING].freeze
|
13
|
+
ACCEPTABLES = [true, false, TRUE_STRING, FALSE_STRING].freeze
|
10
14
|
|
11
15
|
##
|
12
16
|
# Class Methods
|
@@ -21,20 +25,21 @@ module Protobuf
|
|
21
25
|
# #
|
22
26
|
|
23
27
|
def acceptable?(val)
|
24
|
-
val
|
28
|
+
ACCEPTABLES.include?(val)
|
25
29
|
end
|
26
30
|
|
27
31
|
def coerce!(val)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
if TRUE_VALUES.include?(val)
|
33
|
+
true
|
34
|
+
elsif FALSE_VALUES.include?(val)
|
35
|
+
false
|
36
|
+
else
|
37
|
+
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{val.class}'"
|
38
|
+
end
|
34
39
|
end
|
35
40
|
|
36
41
|
def decode(value)
|
37
|
-
value ==
|
42
|
+
value == ONE
|
38
43
|
end
|
39
44
|
|
40
45
|
def encode(value)
|
@@ -27,30 +27,19 @@ module Protobuf
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def decode(bytes)
|
30
|
-
|
31
|
-
|
32
|
-
bytes_to_decode
|
30
|
+
bytes.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
|
31
|
+
bytes
|
33
32
|
end
|
34
33
|
|
35
34
|
def encode(value)
|
36
|
-
value_to_encode =
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
35
|
+
value_to_encode = if value.is_a?(::Protobuf::Message)
|
36
|
+
value.encode
|
37
|
+
else
|
38
|
+
"" + value
|
39
|
+
end
|
42
40
|
|
43
41
|
value_to_encode.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
|
44
|
-
|
45
|
-
|
46
|
-
"#{string_size}#{value_to_encode}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def encode_to_stream(value, stream)
|
50
|
-
value = value.encode if value.is_a?(::Protobuf::Message)
|
51
|
-
byte_size = ::Protobuf::Field::VarintField.encode(value.bytesize)
|
52
|
-
|
53
|
-
stream << tag_encoded << byte_size << value
|
42
|
+
"#{::Protobuf::Field::VarintField.encode(value_to_encode.bytesize)}#{value_to_encode}"
|
54
43
|
end
|
55
44
|
|
56
45
|
def wire_type
|
@@ -15,18 +15,18 @@ module Protobuf
|
|
15
15
|
##
|
16
16
|
# Public Instance Methods
|
17
17
|
#
|
18
|
-
|
19
|
-
def acceptable?(val)
|
20
|
-
!type_class.fetch(val).nil?
|
21
|
-
end
|
22
|
-
|
23
18
|
def encode(value)
|
24
|
-
|
19
|
+
# original Google's library uses 64bits integer for negative value
|
20
|
+
::Protobuf::Field::VarintField.encode(value.to_i & 0xffff_ffff_ffff_ffff)
|
25
21
|
end
|
26
22
|
|
27
23
|
def decode(value)
|
28
|
-
|
29
|
-
|
24
|
+
value -= 0x1_0000_0000_0000_0000 if (value & 0x8000_0000_0000_0000).nonzero?
|
25
|
+
value if acceptable?(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def acceptable?(val)
|
29
|
+
!type_class.fetch(val).nil?
|
30
30
|
end
|
31
31
|
|
32
32
|
def enum?
|
@@ -34,9 +34,7 @@ module Protobuf
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def coerce!(value)
|
37
|
-
|
38
|
-
fail TypeError, "Invalid Enum value: #{value.inspect} for #{name}" unless enum_value
|
39
|
-
enum_value
|
37
|
+
type_class.fetch(value) || fail(TypeError, "Invalid Enum value: #{value.inspect} for #{name}")
|
40
38
|
end
|
41
39
|
|
42
40
|
private
|
@@ -16,6 +16,19 @@ module Protobuf
|
|
16
16
|
INT64_MIN
|
17
17
|
end
|
18
18
|
|
19
|
+
##
|
20
|
+
# Instance Methods
|
21
|
+
#
|
22
|
+
def acceptable?(val)
|
23
|
+
if val.is_a?(Integer) || val.is_a?(Numeric)
|
24
|
+
val >= INT64_MIN && val <= INT64_MAX
|
25
|
+
else
|
26
|
+
Integer(val, 10) >= INT64_MIN && Integer(val, 10) <= INT64_MAX
|
27
|
+
end
|
28
|
+
rescue
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
19
32
|
end
|
20
33
|
end
|
21
34
|
end
|
@@ -14,28 +14,33 @@ module Protobuf
|
|
14
14
|
# Public Instance Methods
|
15
15
|
#
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
bytes_to_decode.force_encoding(::Protobuf::Field::StringField::ENCODING)
|
20
|
-
bytes_to_decode
|
17
|
+
def acceptable?(val)
|
18
|
+
val.is_a?(String) || val.nil? || val.is_a?(Symbol)
|
21
19
|
end
|
22
20
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def coerce!(value)
|
22
|
+
if value.nil?
|
23
|
+
nil
|
24
|
+
elsif acceptable?(value)
|
25
|
+
value.to_s
|
26
|
+
else
|
27
|
+
fail TypeError, "Unacceptable value #{value} for field #{name} of type #{type_class}"
|
28
|
+
end
|
29
|
+
end
|
27
30
|
|
28
|
-
|
31
|
+
def decode(bytes)
|
32
|
+
bytes.force_encoding(::Protobuf::Field::StringField::ENCODING)
|
33
|
+
bytes
|
29
34
|
end
|
30
35
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
def encode(value)
|
37
|
+
value_to_encode = "" + value # dup is slower
|
38
|
+
unless value_to_encode.encoding == ENCODING
|
39
|
+
value_to_encode.encode!(::Protobuf::Field::StringField::ENCODING, :invalid => :replace, :undef => :replace, :replace => "")
|
35
40
|
end
|
41
|
+
value_to_encode.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
|
36
42
|
|
37
|
-
|
38
|
-
stream << tag_encoded << byte_size << value
|
43
|
+
"#{::Protobuf::Field::VarintField.encode(value_to_encode.bytesize)}#{value_to_encode}"
|
39
44
|
end
|
40
45
|
|
41
46
|
def json_encode(value)
|
@@ -7,8 +7,6 @@ module Protobuf
|
|
7
7
|
##
|
8
8
|
# Constants
|
9
9
|
#
|
10
|
-
|
11
|
-
CACHE_LIMIT = 2048
|
12
10
|
INT32_MAX = 2**31 - 1
|
13
11
|
INT32_MIN = -2**31
|
14
12
|
INT64_MAX = 2**63 - 1
|
@@ -24,27 +22,8 @@ module Protobuf
|
|
24
22
|
0
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
def self.cached_varint(value)
|
30
|
-
@_varint_cache ||= {}
|
31
|
-
(@_varint_cache[value] ||= encode(value, false)).dup
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.encode(value, use_cache = true)
|
35
|
-
return cached_varint(value) if use_cache && value >= 0 && value <= CACHE_LIMIT
|
36
|
-
|
37
|
-
bytes = []
|
38
|
-
until value < 128
|
39
|
-
bytes << (0x80 | (value & 0x7f))
|
40
|
-
value >>= 7
|
41
|
-
end
|
42
|
-
(bytes << value).pack('C*')
|
43
|
-
end
|
44
|
-
|
45
|
-
# Load the cache of VarInts on load of file
|
46
|
-
(0..CACHE_LIMIT).each do |cached_value|
|
47
|
-
cached_varint(cached_value)
|
25
|
+
def self.encode(value)
|
26
|
+
::Protobuf::Varint.encode(value)
|
48
27
|
end
|
49
28
|
|
50
29
|
##
|
@@ -66,9 +45,17 @@ module Protobuf
|
|
66
45
|
end
|
67
46
|
|
68
47
|
def coerce!(val)
|
69
|
-
|
70
|
-
|
71
|
-
|
48
|
+
if val.is_a?(Integer) && val >= 0 && val <= INT32_MAX
|
49
|
+
val
|
50
|
+
else
|
51
|
+
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{val.class}'" unless acceptable?(val)
|
52
|
+
|
53
|
+
if val.is_a?(Integer) || val.is_a?(Numeric)
|
54
|
+
val.to_i
|
55
|
+
else
|
56
|
+
Integer(val, 10)
|
57
|
+
end
|
58
|
+
end
|
72
59
|
rescue ArgumentError
|
73
60
|
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{val.class}'"
|
74
61
|
end
|
data/lib/protobuf/message.rb
CHANGED
@@ -1,15 +1,5 @@
|
|
1
1
|
require 'protobuf/message/fields'
|
2
2
|
require 'protobuf/message/serialization'
|
3
|
-
|
4
|
-
# Under MRI, this optimizes proto decoding by around 15% in tests.
|
5
|
-
# When unavailable, we fall to pure Ruby.
|
6
|
-
# rubocop:disable Lint/HandleExceptions
|
7
|
-
begin
|
8
|
-
require 'varint/varint'
|
9
|
-
rescue LoadError
|
10
|
-
end
|
11
|
-
# rubocop:enable Lint/HandleExceptions
|
12
|
-
|
13
3
|
require 'protobuf/varint'
|
14
4
|
|
15
5
|
module Protobuf
|
@@ -80,37 +70,26 @@ module Protobuf
|
|
80
70
|
end
|
81
71
|
|
82
72
|
def each_field_for_serialization
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
fail ::Protobuf::SerializationError, "Required field #{self.class.name}##{field.name} does not have a value." if field.required?
|
87
|
-
next
|
88
|
-
end
|
89
|
-
if field.map?
|
90
|
-
# on-the-wire, maps are represented like an array of entries where
|
91
|
-
# each entry is a message of two fields, key and value.
|
92
|
-
array = Array.new(value.size)
|
93
|
-
i = 0
|
94
|
-
value.each do |k, v|
|
95
|
-
array[i] = field.type_class.new(:key => k, :value => v)
|
96
|
-
i += 1
|
97
|
-
end
|
98
|
-
value = array
|
99
|
-
end
|
73
|
+
_protobuf_message_unset_required_field_tags.each do |tag|
|
74
|
+
fail ::Protobuf::SerializationError, "Required field #{self.class.name}##{_protobuf_message_field[tag].name} does not have a value."
|
75
|
+
end
|
100
76
|
|
101
|
-
|
77
|
+
@values.each_key do |fully_qualified_name|
|
78
|
+
field = _protobuf_message_field[fully_qualified_name]
|
79
|
+
yield(field, field.value_from_values_for_serialization(@values))
|
102
80
|
end
|
103
81
|
end
|
104
82
|
|
105
83
|
def field?(name)
|
106
|
-
field =
|
107
|
-
|
108
|
-
if field
|
109
|
-
|
84
|
+
field = _protobuf_message_field[name]
|
85
|
+
|
86
|
+
if field
|
87
|
+
field.field?(@values)
|
110
88
|
else
|
111
|
-
|
89
|
+
false
|
112
90
|
end
|
113
91
|
end
|
92
|
+
alias :respond_to_has? field?
|
114
93
|
::Protobuf.deprecator.define_deprecated_methods(self, :has_field? => :field?)
|
115
94
|
|
116
95
|
def inspect
|
@@ -121,13 +100,14 @@ module Protobuf
|
|
121
100
|
"#<#{self.class} #{attrs}>"
|
122
101
|
end
|
123
102
|
|
124
|
-
def respond_to_has?(key)
|
125
|
-
respond_to?(key) && field?(key)
|
126
|
-
end
|
127
|
-
|
128
103
|
def respond_to_has_and_present?(key)
|
129
|
-
|
130
|
-
|
104
|
+
field = _protobuf_message_field[key]
|
105
|
+
|
106
|
+
if field
|
107
|
+
field.field_and_present?(@values)
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
131
111
|
end
|
132
112
|
|
133
113
|
# Return a hash-representation of the given fields for this message type.
|
@@ -135,10 +115,19 @@ module Protobuf
|
|
135
115
|
result = {}
|
136
116
|
|
137
117
|
@values.each_key do |field_name|
|
138
|
-
|
139
|
-
field
|
140
|
-
|
141
|
-
|
118
|
+
field = _protobuf_message_field[field_name]
|
119
|
+
field.to_message_hash(@values, result)
|
120
|
+
end
|
121
|
+
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_hash_with_string_keys
|
126
|
+
result = {}
|
127
|
+
|
128
|
+
@values.each_key do |field_name|
|
129
|
+
field = _protobuf_message_field[field_name]
|
130
|
+
field.to_message_hash_with_string_key(@values, result)
|
142
131
|
end
|
143
132
|
|
144
133
|
result
|
@@ -186,11 +175,8 @@ module Protobuf
|
|
186
175
|
end
|
187
176
|
|
188
177
|
def [](name)
|
189
|
-
field =
|
190
|
-
|
191
|
-
return @values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldHash.new(field) if field.map?
|
192
|
-
return @values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldArray.new(field) if field.repeated?
|
193
|
-
@values.fetch(field.fully_qualified_name, field.default_value)
|
178
|
+
field = _protobuf_message_field[name]
|
179
|
+
field.value_from_values(@values)
|
194
180
|
rescue # not having a field should be the exceptional state
|
195
181
|
raise if field
|
196
182
|
fail ArgumentError, "invalid field name=#{name.inspect}"
|
@@ -200,6 +186,16 @@ module Protobuf
|
|
200
186
|
set_field(name, value, true)
|
201
187
|
end
|
202
188
|
|
189
|
+
def set_field(name, value, ignore_nil_for_repeated, field = nil)
|
190
|
+
field ||= _protobuf_message_field[name]
|
191
|
+
|
192
|
+
if field
|
193
|
+
field.set_field(@values, value, ignore_nil_for_repeated, self)
|
194
|
+
else
|
195
|
+
fail(::Protobuf::FieldNotDefinedError, name) unless ::Protobuf.ignore_unknown_fields?
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
203
199
|
##
|
204
200
|
# Instance Aliases
|
205
201
|
#
|
@@ -222,57 +218,6 @@ module Protobuf
|
|
222
218
|
|
223
219
|
private
|
224
220
|
|
225
|
-
# rubocop:disable Metrics/MethodLength
|
226
|
-
def set_field(name, value, ignore_nil_for_repeated)
|
227
|
-
if (field = self.class.get_field(name, true))
|
228
|
-
if field.map?
|
229
|
-
unless value.is_a?(Hash)
|
230
|
-
fail TypeError, <<-TYPE_ERROR
|
231
|
-
Expected map value
|
232
|
-
Got '#{value.class}' for map protobuf field #{field.name}
|
233
|
-
TYPE_ERROR
|
234
|
-
end
|
235
|
-
|
236
|
-
if value.empty?
|
237
|
-
@values.delete(field.fully_qualified_name)
|
238
|
-
else
|
239
|
-
@values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldHash.new(field)
|
240
|
-
@values[field.fully_qualified_name].replace(value)
|
241
|
-
end
|
242
|
-
elsif field.repeated?
|
243
|
-
if value.nil? && ignore_nil_for_repeated
|
244
|
-
::Protobuf.deprecator.deprecation_warning("#{self.class}#[#{name}]=nil", "use an empty array instead of nil")
|
245
|
-
return
|
246
|
-
end
|
247
|
-
unless value.is_a?(Array)
|
248
|
-
fail TypeError, <<-TYPE_ERROR
|
249
|
-
Expected repeated value of type '#{field.type_class}'
|
250
|
-
Got '#{value.class}' for repeated protobuf field #{field.name}
|
251
|
-
TYPE_ERROR
|
252
|
-
end
|
253
|
-
|
254
|
-
value = value.compact
|
255
|
-
|
256
|
-
if value.empty?
|
257
|
-
@values.delete(field.fully_qualified_name)
|
258
|
-
else
|
259
|
-
@values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldArray.new(field)
|
260
|
-
@values[field.fully_qualified_name].replace(value)
|
261
|
-
end
|
262
|
-
else
|
263
|
-
if value.nil? # rubocop:disable Style/IfInsideElse
|
264
|
-
@values.delete(field.fully_qualified_name)
|
265
|
-
else
|
266
|
-
@values[field.fully_qualified_name] = field.coerce!(value)
|
267
|
-
end
|
268
|
-
end
|
269
|
-
else
|
270
|
-
unless ::Protobuf.ignore_unknown_fields?
|
271
|
-
fail ::Protobuf::FieldNotDefinedError, name
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
221
|
def copy_to(object, method)
|
277
222
|
duplicate = proc do |obj|
|
278
223
|
case obj
|