ruby_protobuf 0.3.2 → 0.3.3

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 (39) hide show
  1. data/History.txt +7 -2
  2. data/Manifest.txt +74 -0
  3. data/README.txt +1 -1
  4. data/Rakefile +5 -5
  5. data/bin/rprotoc +25 -10
  6. data/{test/proto → examples}/addressbook.pb.rb +1 -14
  7. data/examples/addressbook.proto +24 -0
  8. data/examples/reading_a_message.rb +32 -0
  9. data/examples/writing_a_message.rb +46 -0
  10. data/lib/protobuf/compiler/compiler.rb +9 -11
  11. data/lib/protobuf/compiler/nodes.rb +15 -7
  12. data/lib/protobuf/compiler/proto.y +56 -36
  13. data/lib/protobuf/compiler/proto_parser.rb +373 -236
  14. data/lib/protobuf/compiler/visitors.rb +5 -1
  15. data/lib/protobuf/descriptor/enum_descriptor.rb +1 -1
  16. data/lib/protobuf/message/decoder.rb +12 -19
  17. data/lib/protobuf/message/encoder.rb +5 -2
  18. data/lib/protobuf/message/enum.rb +1 -1
  19. data/lib/protobuf/message/field.rb +302 -298
  20. data/lib/protobuf/message/message.rb +63 -35
  21. data/lib/ruby_protobuf.rb +1 -1
  22. data/{bin → script}/mk_parser +0 -0
  23. data/test/merge.rb +1 -1
  24. data/test/proto/types.proto +20 -0
  25. data/test/test_addressbook.rb +1 -0
  26. data/test/test_compiler.rb +21 -7
  27. data/test/test_message.rb +19 -0
  28. data/test/test_optional_field.rb +80 -0
  29. data/test/test_repeated_types.rb +106 -0
  30. data/test/test_serialize.rb +34 -0
  31. data/test/test_standard_message.rb +10 -0
  32. data/test/test_types.rb +49 -4
  33. data/test/types.rb +23 -2
  34. metadata +22 -20
  35. data/lib/protobuf/compiler/compiler_old.rb +0 -123
  36. data/test/proto/addressbook.rb +0 -69
  37. data/test/proto/bool_default.pb.rb +0 -16
  38. data/test/proto/bool_default.proto +0 -3
  39. data/test/proto/float_default.proto +0 -2
@@ -48,7 +48,11 @@ module Protobuf
48
48
  end
49
49
 
50
50
  def commented_proto_contents
51
- File.read(proto_file).gsub(/^/, '# ') if proto_file
51
+ if proto_file
52
+ proto_filepath = File.exist?(proto_file) ?
53
+ proto_file : "#{@proto_dir}/#{proto_file}"
54
+ File.read(proto_filepath).gsub(/^/, '# ')
55
+ end
52
56
  end
53
57
 
54
58
  def write(str)
@@ -22,7 +22,7 @@ module Protobuf
22
22
  enum_proto.name = @enum_class.name.split('::').last
23
23
  @enum_class.constants.each do |const|
24
24
  enum_value_proto = Google::Protobuf::EnumValueDescriptorProto.new
25
- enum_value_proto.name = const
25
+ enum_value_proto.name = const.to_s
26
26
  enum_value_proto.number = @enum_class.const_get const
27
27
  enum_proto.value << enum_value_proto
28
28
  end
@@ -42,39 +42,36 @@ module Protobuf
42
42
  protected
43
43
 
44
44
  def read_key(stream)
45
- # TODO is there more clear way to do this?
46
- bits = 0
47
45
  bytes = read_varint stream
48
- bytes.each_with_index do |byte, index|
49
- byte &= 0b01111111
50
- bits |= byte << (7 * index)
51
- end
52
- wire_type = bits & 0b00000111
46
+ bits = Protobuf::Field::VarintField.decode bytes
47
+ wire_type = bits & 0x07
53
48
  tag = bits >> 3
54
49
  [tag, wire_type]
55
50
  end
56
51
 
57
52
  def read_varint(stream)
53
+ read_method = stream.respond_to?(:readbyte) ? :readbyte : :readchar
58
54
  bytes = []
59
55
  begin
60
- byte = stream.readchar
61
- bytes << (byte & 0b01111111)
62
- end while byte >> 7 == 1
56
+ byte = stream.send(read_method)
57
+ bytes << (byte & 0x7f)
58
+ end while (byte & 0x80).nonzero?
63
59
  bytes
64
60
  end
65
61
 
62
+ def read_fixed32(stream)
63
+ stream.read(4)
64
+ end
65
+
66
66
  def read_fixed64(stream)
67
67
  stream.read(8)
68
68
  end
69
69
 
70
70
  def read_length_delimited(stream)
71
71
  bytes = read_varint stream
72
- value_length = 0
73
- bytes.each_with_index do |byte, index|
74
- value_length |= byte << (7 * index)
75
- end
72
+ value_length = Protobuf::Field::VarintField.decode bytes
76
73
  value = stream.read value_length
77
- value.unpack('c*')
74
+ value.unpack('C*')
78
75
  end
79
76
 
80
77
  def read_start_group(stream)
@@ -84,9 +81,5 @@ module Protobuf
84
81
  def read_end_group(stream)
85
82
  raise NotImplementedError.new('Group is duplecated.')
86
83
  end
87
-
88
- def read_fixed32(stream)
89
- stream.read(4)
90
- end
91
84
  end
92
85
  end
@@ -1,6 +1,8 @@
1
1
  require 'protobuf/common/wire_type'
2
2
 
3
3
  module Protobuf
4
+ class NotInitializedError < StandardError; end
5
+
4
6
  class Encoder
5
7
  class <<self
6
8
  def encode(stream, message)
@@ -13,8 +15,9 @@ module Protobuf
13
15
  end
14
16
 
15
17
  def encode(stream=@stream, message=@message)
18
+ raise NotInitializedError unless message.initialized?
16
19
  message.each_field do |field, value|
17
- next unless value # TODO
20
+ next unless message.has_field?(field.name)
18
21
 
19
22
  if field.repeated?
20
23
  value.each do |val|
@@ -28,7 +31,7 @@ module Protobuf
28
31
 
29
32
  def write_pair(field, value, stream)
30
33
  key = (field.tag << 3) | field.wire_type
31
- key_bytes = Protobuf::Field::VarintField.get_bytes key
34
+ key_bytes = Protobuf::Field::VarintField.encode key
32
35
  stream.write key_bytes
33
36
  bytes = field.get value
34
37
  stream.write bytes
@@ -8,7 +8,7 @@ module Protobuf
8
8
 
9
9
  def get_name_by_tag(tag)
10
10
  constants.find do |name|
11
- class_eval(name) == tag
11
+ const_get(name) == tag
12
12
  end
13
13
  end
14
14
 
@@ -4,9 +4,9 @@ require 'protobuf/descriptor/field_descriptor'
4
4
  module Protobuf
5
5
  module Field
6
6
  def self.build(message_class, rule, type, name, tag, opts={})
7
- field_class =
8
- if [:double, :float, :int32, :int64, :uint32, :uint64,
9
- :sint32, :sint64, :fixed32, :fixed64, :sfixed32, :sfixed64,
7
+ field_class =
8
+ if [:double, :float, :int32, :int64, :uint32, :uint64,
9
+ :sint32, :sint64, :fixed32, :fixed64, :sfixed32, :sfixed64,
10
10
  :bool, :string, :bytes].include? type
11
11
  eval "Protobuf::Field::#{type.to_s.capitalize}Field"
12
12
  else
@@ -22,6 +22,8 @@ module Protobuf
22
22
  def descriptor
23
23
  @descriptor ||= Protobuf::Descriptor::FieldDescriptor.new
24
24
  end
25
+
26
+ def default; nil end
25
27
  end
26
28
 
27
29
  attr_accessor :message_class, :rule, :type, :name, :tag, :default
@@ -31,9 +33,10 @@ module Protobuf
31
33
  end
32
34
 
33
35
  def initialize(message_class, rule, type, name, tag, opts={})
34
- @message_class, @rule, @type, @name, @tag, @default, @extension =
36
+ @message_class, @rule, @type, @name, @tag, @default, @extension =
35
37
  message_class, rule, type, name, tag, opts[:default], opts[:extension]
36
38
  @error_message = 'Type invalid'
39
+ define_accessor
37
40
  end
38
41
 
39
42
  def ready?; true end
@@ -44,9 +47,11 @@ module Protobuf
44
47
  return false if message[name].nil?
45
48
  return false if is_a?(Protobuf::Field::MessageField) and not message[name].initialized?
46
49
  when :repeated
47
- return message[name].inject(true) do |result, msg|
48
- result and msg.initialized?
49
- end
50
+ return message[name].all? {|msg|
51
+ (not is_a?(Protobuf::Field::MessageField)) or msg.initialized?
52
+ }
53
+ when :optional
54
+ return false if message[name] and is_a?(Protobuf::Field::MessageField) and not message[name].initialized?
50
55
  end
51
56
  true
52
57
  end
@@ -55,7 +60,7 @@ module Protobuf
55
60
  if repeated?
56
61
  message[name].clear
57
62
  else
58
- message[name] = default_value
63
+ message.instance_variable_get(:@values).delete(name)
59
64
  end
60
65
  end
61
66
 
@@ -73,60 +78,81 @@ module Protobuf
73
78
  end
74
79
 
75
80
  def typed_default_value(default=nil)
76
- default
81
+ default or self.class.default
77
82
  end
78
83
 
79
- def define_accessor(message_instance)
80
- message_instance.instance_variable_set "@#{name}", default_value
81
- define_getter message_instance
82
- define_setter message_instance unless rule == :repeated
84
+ private
85
+
86
+ def define_accessor
87
+ define_getter
88
+ if rule == :repeated
89
+ define_array_setter
90
+ else
91
+ define_setter
92
+ end
83
93
  end
84
94
 
85
- def define_getter(message_instance)
86
- message_instance.instance_eval %Q{
87
- def #{name}
88
- @#{name}
95
+ def define_getter
96
+ field = self
97
+ @message_class.class_eval do
98
+ define_method(field.name) do
99
+ if @values.has_key?(field.name)
100
+ @values[field.name]
101
+ else
102
+ field.default_value
103
+ end
89
104
  end
90
- }
105
+ end
91
106
  end
92
107
 
93
- def define_setter(message_instance)
94
- extension = @extension
95
- message_instance.instance_eval %Q{
96
- def #{name}=(val)
97
- field = get_#{extension ? 'ext_' : ''}field_by_name #{name.inspect}
108
+ def define_setter
109
+ field = self
110
+ @message_class.class_eval do
111
+ define_method("#{field.name}=") do |val|
98
112
  if val.nil?
99
- @#{name} = field.default_value
113
+ @values.delete(field.name)
100
114
  elsif field.acceptable? val
101
- @#{name} = val
115
+ @values[field.name] = val
102
116
  end
103
117
  end
104
- }
118
+ end
119
+ end
120
+
121
+ def define_array_setter
122
+ field = self
123
+ @message_class.class_eval do
124
+ define_method("#{field.name}=") do |val|
125
+ @values[field.name].replace(val)
126
+ end
127
+ end
105
128
  end
106
129
 
130
+ public
131
+
132
+ # encoder/decoder related methods
133
+
107
134
  def set(message_instance, bytes)
135
+ value = decode(bytes)
108
136
  if repeated?
109
- set_array message_instance, bytes
137
+ message_instance.send(name) << value
110
138
  else
111
- set_bytes message_instance, bytes
139
+ message_instance.send("#{name}=", value)
112
140
  end
113
141
  end
114
142
 
115
- def set_array(message_instance, bytes)
116
- raise NotImplementedError
143
+ def get(value)
144
+ encode(value)
117
145
  end
118
146
 
119
- def set_bytes(message_instance, bytes)
120
- raise NotImplementedError
147
+ def decode(bytes)
148
+ raise NotImplementedError.new("#{self.class.name}\#decode")
121
149
  end
150
+ private :decode
122
151
 
123
- def get(value)
124
- get_bytes value
125
- end
126
-
127
- def get_bytes(value)
128
- raise NotImplementedError
152
+ def encode(value)
153
+ raise NotImplementedError.new("#{self.class.name}\#encode")
129
154
  end
155
+ private :encode
130
156
 
131
157
  def merge(message_instance, value)
132
158
  if repeated?
@@ -137,13 +163,15 @@ module Protobuf
137
163
  end
138
164
 
139
165
  def merge_array(message_instance, value)
140
- message_instance[tag].concat value
166
+ message_instance[tag].concat value
141
167
  end
142
168
 
143
169
  def merge_value(message_instance, value)
144
170
  message_instance[tag] = value
145
171
  end
146
172
 
173
+ # utility methods
174
+
147
175
  def repeated?; rule == :repeated end
148
176
  def required?; rule == :required end
149
177
  def optional?; rule == :optional end
@@ -180,22 +208,26 @@ module Protobuf
180
208
  elsif type.superclass == Protobuf::Message
181
209
  Protobuf::Field::MessageField
182
210
  else
183
- raise $!
211
+ raise TypeError.new(type.inspect)
184
212
  end
185
213
  field_class.new @message_class, @rule, type, @name, @tag, @opts
186
214
  end
187
215
 
188
216
  def typename_to_class(message_class, type)
217
+ suffix = type.to_s.split('::')
189
218
  modules = message_class.to_s.split('::')
219
+ args = (Object.method(:const_defined?).arity == 1) ? [] : [nil, false]
190
220
  while
191
- begin
192
- type = eval((modules | [type.to_s]).join('::'))
193
- break
194
- rescue NameError
195
- modules.empty? ? raise($!) : modules.pop
196
- end
221
+ mod = modules.empty? ? Object : eval(modules.join('::'))
222
+ mod = suffix.inject(mod) {|m, s|
223
+ args[0] = s
224
+ m and m.const_defined?(*args) and m.const_get(s)
225
+ }
226
+ break if mod
227
+ raise NameError.new("type not found: #{type}", type) if modules.empty?
228
+ modules.pop
197
229
  end
198
- type
230
+ mod
199
231
  end
200
232
  end
201
233
 
@@ -205,136 +237,119 @@ module Protobuf
205
237
  end
206
238
 
207
239
  def []=(nth, val)
208
- if @field.acceptable? val
209
- super
210
- end
240
+ super(normalize(val))
211
241
  end
212
242
 
213
243
  def <<(val)
214
- if @field.acceptable? val
215
- super
216
- end
244
+ super(normalize(val))
217
245
  end
218
246
 
219
247
  def push(val)
220
- if @field.acceptable? val
221
- super
222
- end
248
+ super(normalize(val))
223
249
  end
224
250
 
225
251
  def unshift(val)
226
- if @field.acceptable? val
227
- super
228
- end
252
+ super(normalize(val))
229
253
  end
230
254
 
231
- def to_s
232
- "[#{@field.name}]"
255
+ def replace(val)
256
+ raise TypeError unless val.is_a?(Array)
257
+ val = val.map {|v| normalize(v)}
258
+ super(val)
233
259
  end
234
- end
235
260
 
236
- class StringField < BaseField
237
- def wire_type
238
- Protobuf::WireType::LENGTH_DELIMITED
261
+ def to_s
262
+ "[#{@field.name}]"
239
263
  end
240
264
 
241
- def typed_default_value(default=nil)
242
- default or ''
243
- end
265
+ private
244
266
 
245
- def acceptable?(val)
246
- raise TypeError unless val.instance_of? String
247
- true
267
+ def normalize(val)
268
+ raise TypeError unless @field.acceptable?(val)
269
+ if @field.is_a?(MessageField) && val.is_a?(Hash)
270
+ @field.type.new(val)
271
+ else
272
+ val
273
+ end
248
274
  end
275
+ end
249
276
 
250
- def set_bytes(message_instance, bytes)
251
- message_instance.send("#{name}=", bytes.pack('U*'))
252
- end
253
-
254
- def set_array(message_instance, bytes)
255
- message = bytes.pack('U*')
256
- arr = message_instance.send name
257
- arr << message
277
+ class BytesField < BaseField
278
+ class <<self
279
+ def default; '' end
258
280
  end
259
281
 
260
- def get_bytes(value)
261
- bytes = value.unpack('U*')
262
- string_size = VarintField.get_bytes bytes.size
263
- #(string_size + bytes).pack('C*')
264
- string_size + bytes.pack('C*')
265
- end
266
- end
267
-
268
- class BytesField < BaseField
269
282
  def wire_type
270
283
  Protobuf::WireType::LENGTH_DELIMITED
271
284
  end
272
285
 
273
- def typed_default_value(default=nil)
274
- default or ''
275
- end
276
-
277
286
  def acceptable?(val)
278
287
  raise TypeError unless val.instance_of? String
279
288
  true
280
289
  end
281
290
 
282
- def set_bytes(message_instance, bytes)
283
- message_instance.send("#{name}=", bytes.pack('C*'))
291
+ def decode(bytes)
292
+ bytes.pack('C*')
284
293
  end
285
-
286
- def set_array(message_instance, bytes)
287
- message = bytes.pack('C*')
288
- arr = message_instance.send name
289
- arr << message
294
+
295
+ def encode(value)
296
+ value = value.dup
297
+ value.force_encoding('ASCII-8BIT') if value.respond_to?(:force_encoding)
298
+ string_size = VarintField.encode(value.size)
299
+ string_size << value
290
300
  end
301
+ end
291
302
 
292
- def get_bytes(value)
293
- string_size = VarintField.get_bytes value.unpack('C*').size
294
- string_size + value
303
+ class StringField < BytesField
304
+ def decode(bytes)
305
+ message = bytes.pack('C*')
306
+ message.force_encoding('UTF-8') if message.respond_to?(:force_encoding)
307
+ message
295
308
  end
296
309
  end
297
310
 
298
311
  class VarintField < BaseField
299
- def wire_type
300
- Protobuf::WireType::VARINT
301
- end
312
+ INT32_MAX = 2**31 - 1
313
+ INT32_MIN = -2**31
314
+ INT64_MAX = 2**63 - 1
315
+ INT64_MIN = -2**63
316
+ UINT32_MAX = 2**32 - 1
317
+ UINT64_MAX = 2**64 - 1
302
318
 
303
- def typed_default_value(default=nil)
304
- default or 0
305
- end
306
-
307
- def set_bytes(message_instance, bytes)
308
- # TODO should refactor using pack('w*')
309
- value = 0
310
- bytes.each_with_index do |byte, index|
311
- value |= byte << (7 * index)
319
+ class <<self
320
+ def default; 0 end
321
+
322
+ def decode(bytes)
323
+ value = 0
324
+ bytes.each_with_index do |byte, index|
325
+ value |= byte << (7 * index)
326
+ end
327
+ value
312
328
  end
313
- message_instance.send("#{name}=", value)
314
- end
315
-
316
- def self.get_bytes(value)
317
- # TODO should refactor using unpack('w*')
318
- #return [value].pack('w*').unpack('C*')
319
- return [0].pack('C') if value == 0
320
- bytes = []
321
- until value == 0
322
- byte = 0
323
- 7.times do |i|
324
- byte |= (value & 1) << i
325
- value >>= 1
329
+
330
+ def encode(value)
331
+ raise RangeError.new(value) if value < 0
332
+ return [value].pack('C') if value < 128
333
+ bytes = []
334
+ until value == 0
335
+ bytes << (0x80 | (value & 0x7f))
336
+ value >>= 7
326
337
  end
327
- byte |= 0b10000000
328
- bytes << byte
338
+ bytes[-1] &= 0x7f
339
+ bytes.pack('C*')
329
340
  end
330
- #bytes[0] &= 0b01111111
331
- #bytes
332
- bytes[bytes.size - 1] &= 0b01111111
333
- bytes.pack('C*')
334
341
  end
335
342
 
336
- def get_bytes(value)
337
- self.class.get_bytes value
343
+ def wire_type
344
+ Protobuf::WireType::VARINT
345
+ end
346
+
347
+ def decode(bytes)
348
+ self.class.decode(bytes)
349
+ end
350
+
351
+ def encode(value)
352
+ self.class.encode(value)
338
353
  end
339
354
 
340
355
  def acceptable?(val)
@@ -343,92 +358,86 @@ module Protobuf
343
358
  true
344
359
  end
345
360
  end
346
-
347
- class Int32Field < VarintField
348
- def self.max; 1.0/0.0 end
349
- def self.min; -1.0/0.0 end
361
+
362
+ # Base class for int32 and int64
363
+ class IntegerField < VarintField
364
+ def encode(value)
365
+ # original Google's library uses 64bits integer for negative value
366
+ VarintField.encode(value & 0xffff_ffff_ffff_ffff)
367
+ end
368
+
369
+ def decode(bytes)
370
+ value = VarintField.decode(bytes)
371
+ value -= 0x1_0000_0000_0000_0000 if (value & 0x8000_0000_0000_0000).nonzero?
372
+ value
373
+ end
350
374
  end
351
-
352
- class Int64Field < VarintField
353
- def self.max; 1.0/0.0 end
354
- def self.min; -1.0/0.0 end
375
+
376
+ class Int32Field < IntegerField
377
+ def self.max; INT32_MAX; end
378
+ def self.min; INT32_MIN; end
355
379
  end
356
-
380
+
381
+ class Int64Field < IntegerField
382
+ def self.max; INT64_MAX; end
383
+ def self.min; INT64_MIN; end
384
+ end
385
+
357
386
  class Uint32Field < VarintField
358
- def self.max; 1.0/0.0 end
359
- def self.min; 0 end
387
+ def self.max; UINT32_MAX; end
388
+ def self.min; 0; end
360
389
  end
361
-
390
+
362
391
  class Uint64Field < VarintField
363
- def self.max; 1.0/0.0 end
364
- def self.min; 0 end
392
+ def self.max; UINT64_MAX; end
393
+ def self.min; 0; end
365
394
  end
366
-
367
- class Sint32Field < VarintField
368
- def self.max; 1.0/0.0 end
369
- def self.min; -1.0/0.0 end
370
-
371
- def set_bytes(message_instance, bytes)
372
- # TODO use only bit-operations
373
- byte = bytes.first
374
- value =
375
- if byte % 2 == 0
376
- byte / 2
377
- else
378
- -(byte + 1) / 2
379
- end
380
- message_instance.send("#{name}=", value)
395
+
396
+ # Base class for sint32 and sint64
397
+ class SignedIntegerField < VarintField
398
+ def decode(bytes)
399
+ value = VarintField.decode(bytes)
400
+ if (value & 1).zero?
401
+ value >> 1 # positive value
402
+ else
403
+ ~value >> 1 # negative value
404
+ end
381
405
  end
382
406
 
383
- def get_bytes(value)
384
- #(value << 1) ^ (value >> 31)
385
- [(value << 1) ^ (value >> 31)].pack('C*')
407
+ def encode(value)
408
+ if value >= 0
409
+ VarintField.encode(value << 1)
410
+ else
411
+ VarintField.encode(~(value << 1))
412
+ end
386
413
  end
387
414
  end
388
-
389
- class Sint64Field < VarintField
390
- def self.max; 1.0/0.0 end
391
- def self.min; -1.0/0.0 end
392
-
393
- def set_bytes(message_instance, bytes)
394
- # TODO use only bit-operations
395
- byte = bytes.first
396
- value =
397
- if byte % 2 == 0
398
- byte / 2
399
- else
400
- -(byte + 1) / 2
401
- end
402
- message_instance.send("#{name}=", value)
403
- end
404
415
 
405
- def get_bytes(value)
406
- #(value << 1) ^ (value >> 63)
407
- [(value << 1) ^ (value >> 63)].pack('C*')
408
- end
416
+ class Sint32Field < SignedIntegerField
417
+ def self.max; INT32_MAX; end
418
+ def self.min; INT32_MIN; end
409
419
  end
410
-
411
- class DoubleField < VarintField
420
+
421
+ class Sint64Field < SignedIntegerField
422
+ def self.max; INT64_MAX; end
423
+ def self.min; INT64_MIN; end
424
+ end
425
+
426
+ class FloatField < BaseField
427
+ def self.default; 0.0; end
428
+ def self.max; 1.0/0; end
429
+ def self.min; -1.0/0; end
430
+
412
431
  def wire_type
413
- Protobuf::WireType::FIXED64
414
- end
415
-
416
- #TODO
417
- def self.max
418
- '0x7fefffffffffffff'.unpack('d').first
432
+ Protobuf::WireType::FIXED32
419
433
  end
420
434
 
421
- #TODO
422
- def self.min
423
- -(2**(64/2) - 1)
424
- end
425
-
426
- def set_bytes(message_instance, bytes)
427
- message_instance.send("#{name}=", bytes.unpack('E').first)
435
+ def decode(bytes)
436
+ bytes.unpack('e').first
428
437
  end
429
438
 
430
- def get_bytes(value)
431
- [value].pack('E')
439
+ def encode(value)
440
+ [value].pack('e')
432
441
  end
433
442
 
434
443
  def acceptable?(val)
@@ -437,129 +446,129 @@ module Protobuf
437
446
  true
438
447
  end
439
448
  end
440
-
441
- class FloatField < VarintField
449
+
450
+ class DoubleField < FloatField
442
451
  def wire_type
443
- Protobuf::WireType::FIXED32
444
- end
445
-
446
- #TODO
447
- def self.max
448
- '0x7fefffffffffffff'.unpack('e').first
452
+ Protobuf::WireType::FIXED64
449
453
  end
450
454
 
451
- #TODO
452
- def self.min
453
- -(2**(32/2) - 1)
454
- end
455
-
456
- def set_bytes(message_instance, bytes)
457
- message_instance.send("#{name}=", bytes.unpack('e').first)
455
+ def decode(bytes)
456
+ bytes.unpack('E').first
458
457
  end
459
458
 
460
- def get_bytes(value)
461
- [value].pack('e')
462
- end
463
-
464
- def acceptable?(val)
465
- raise TypeError unless val.is_a? Numeric
466
- raise RangeError if val < min or max < val
467
- true
459
+ def encode(value)
460
+ [value].pack('E')
468
461
  end
469
- end
470
-
471
- class Fixed32Field < VarintField
462
+ end
463
+
464
+ class Fixed32Field < Uint32Field
472
465
  def wire_type
473
466
  Protobuf::WireType::FIXED32
474
467
  end
475
468
 
476
- def self.max
477
- 2**32
469
+ def decode(bytes)
470
+ bytes.unpack('V').first
478
471
  end
479
472
 
480
- def self.min
481
- 0
482
- end
483
-
484
- def set_bytes(message_instance, bytes)
485
- message_instance.send("#{name}=", bytes.unpack('L').first)
486
- end
487
-
488
- def get_bytes(value)
489
- [value].pack('L')
473
+ def encode(value)
474
+ [value].pack('V')
490
475
  end
491
476
  end
492
-
493
- class Fixed64Field < VarintField
477
+
478
+ class Fixed64Field < Uint64Field
494
479
  def wire_type
495
480
  Protobuf::WireType::FIXED64
496
481
  end
497
482
 
498
- def self.max
499
- 2**64
500
- end
501
-
502
- def self.min
503
- 0
504
- end
505
-
506
- def set_bytes(message_instance, bytes)
507
- message_instance.send("#{name}=", bytes.unpack('l').first)
483
+ def decode(bytes)
484
+ # we don't use 'Q' for pack/unpack. 'Q' is machine-dependent.
485
+ values = bytes.unpack('VV')
486
+ values[0] + (values[1] << 32)
508
487
  end
509
488
 
510
- def get_bytes(value)
511
- [value].pack('Q')
489
+ def encode(value)
490
+ # we don't use 'Q' for pack/unpack. 'Q' is machine-dependent.
491
+ [value & 0xffff_ffff, value >> 32].pack('VV')
512
492
  end
513
493
  end
514
-
515
- class Sfinxed32Field < VarintField
494
+
495
+ class Sfixed32Field < Int32Field
516
496
  def wire_type
517
497
  Protobuf::WireType::FIXED32
518
498
  end
519
499
 
520
- def self.max
521
- 2**(32/2)
500
+ def decode(bytes)
501
+ value = bytes.unpack('V').first
502
+ value -= 0x1_0000_0000 if (value & 0x8000_0000).nonzero?
503
+ value
522
504
  end
523
505
 
524
- def self.min
525
- -(2**(32/2) - 1)
506
+ def encode(value)
507
+ [value].pack('V')
526
508
  end
527
509
  end
528
-
529
- class Sfixed64Field < VarintField
510
+
511
+ class Sfixed64Field < Int64Field
530
512
  def wire_type
531
513
  Protobuf::WireType::FIXED64
532
514
  end
533
515
 
534
- def self.max
535
- 2**(64/2)
516
+ def decode(bytes)
517
+ # we don't use 'Q' for pack/unpack. 'Q' is machine-dependent.
518
+ values = bytes.unpack('VV')
519
+ value = values[0] + (values[1] << 32)
520
+ value -= 0x1_0000_0000_0000_0000 if (value & 0x8000_0000_0000_0000).nonzero?
521
+ value
536
522
  end
537
523
 
538
- def self.min
539
- -(2**(64/2) - 1)
524
+ def encode(value)
525
+ # we don't use 'Q' for pack/unpack. 'Q' is machine-dependent.
526
+ [value & 0xffff_ffff, value >> 32].pack('VV')
540
527
  end
541
528
  end
542
-
529
+
543
530
  class BoolField < VarintField
544
- def typed_default_value(default=nil)
545
- default or false
531
+ class <<self
532
+ def default; false end
546
533
  end
547
534
 
548
535
  def acceptable?(val)
549
536
  raise TypeError unless [TrueClass, FalseClass].include? val.class
550
537
  true
551
538
  end
552
-
553
- def set_bytes(message_instance, bytes)
554
- message_instance.send("#{name}=", bytes.first == 1)
539
+
540
+ def decode(bytes)
541
+ bytes.first == 1
555
542
  end
556
543
 
557
- def get_bytes(value)
544
+ def encode(value)
558
545
  [value ? 1 : 0].pack('C')
559
546
  end
560
547
  end
561
-
548
+
562
549
  class MessageField < BaseField
550
+ class <<self
551
+ def default; nil end
552
+ end
553
+
554
+ def define_setter
555
+ field = self
556
+ @message_class.class_eval do
557
+ define_method("#{field.name}=") do |val|
558
+ case val
559
+ when nil
560
+ @values.delete(field.name)
561
+ when Hash
562
+ @values[field.name] = field.type.new(val)
563
+ when field.type
564
+ @values[field.name] = val
565
+ else
566
+ raise TypeError
567
+ end
568
+ end
569
+ end
570
+ end
571
+
563
572
  def wire_type
564
573
  Protobuf::WireType::LENGTH_DELIMITED
565
574
  end
@@ -573,33 +582,20 @@ module Protobuf
573
582
  end
574
583
 
575
584
  def acceptable?(val)
576
- raise TypeError unless val.instance_of? type
585
+ raise TypeError unless val.instance_of?(type) or val.instance_of?(Hash)
577
586
  true
578
587
  end
579
-
580
- def set_bytes(message_instance, bytes)
581
- message = type.new
582
- #message.parse_from bytes
583
- message.parse_from_string bytes.pack('U*') # TODO
584
- message_instance.send("#{name}=", message)
585
- end
586
-
587
- def set_array(message_instance, bytes)
588
+
589
+ def decode(bytes)
588
590
  message = type.new
589
- #message.parse_from bytes
590
- message.parse_from_string bytes.pack('U*')
591
- arr = message_instance.send name
592
- arr << message
591
+ message.parse_from_string bytes.pack('C*') # TODO
592
+ message
593
593
  end
594
594
 
595
- def get_bytes(value)
596
- stringio = StringIO.new ''
597
- value.serialize_to stringio
598
- bytes = stringio.string.unpack 'C*'
599
- string_size = VarintField.get_bytes bytes.size
600
- #(string_size + bytes).pack('C*')
601
- #bytes + string_size
602
- string_size + bytes.pack('C*')
595
+ def encode(value)
596
+ bytes = value.serialize_to_string
597
+ string_size = VarintField.encode bytes.size
598
+ string_size << bytes
603
599
  end
604
600
 
605
601
  def merge_value(message_instance, value)
@@ -608,6 +604,14 @@ module Protobuf
608
604
  end
609
605
 
610
606
  class EnumField < VarintField
607
+ def default
608
+ if @default.is_a?(Symbol)
609
+ type.const_get @default
610
+ else
611
+ @default
612
+ end
613
+ end
614
+
611
615
  def acceptable?(val)
612
616
  raise TypeError unless type.valid_tag? val
613
617
  true