ruby_protobuf 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/Manifest.txt +32 -0
- data/README.txt +50 -0
- data/Rakefile +18 -0
- data/bin/rprotoc +21 -0
- data/bin/ruby_protobuf +0 -0
- data/lib/protobuf/compiler.rb +90 -0
- data/lib/protobuf/decoder.rb +87 -0
- data/lib/protobuf/encoder.rb +36 -0
- data/lib/protobuf/enum.rb +13 -0
- data/lib/protobuf/extend.rb +8 -0
- data/lib/protobuf/field.rb +547 -0
- data/lib/protobuf/message.rb +133 -0
- data/lib/protobuf/parser.y +138 -0
- data/lib/protobuf/service.rb +7 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/ruby_protobuf.rb +22 -0
- data/test/addressbook.proto +24 -0
- data/test/addressbook.rb +41 -0
- data/test/data/data.bin +3 -0
- data/test/data/data_source.py +14 -0
- data/test/data/types.bin +0 -0
- data/test/data/types_source.py +22 -0
- data/test/test_addressbook.rb +41 -0
- data/test/test_compiler.rb +39 -0
- data/test/test_message.rb +20 -0
- data/test/test_parse.rb +15 -0
- data/test/test_ruby_protobuf.rb +1 -0
- data/test/test_serialize.rb +27 -0
- data/test/test_types.rb +180 -0
- data/test/types.proto +17 -0
- data/test/types.rb +22 -0
- metadata +102 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/rprotoc
|
6
|
+
bin/ruby_protobuf
|
7
|
+
lib/protobuf/compiler.rb
|
8
|
+
lib/protobuf/decoder.rb
|
9
|
+
lib/protobuf/encoder.rb
|
10
|
+
lib/protobuf/enum.rb
|
11
|
+
lib/protobuf/extend.rb
|
12
|
+
lib/protobuf/field.rb
|
13
|
+
lib/protobuf/message.rb
|
14
|
+
lib/protobuf/parser.y
|
15
|
+
lib/protobuf/service.rb
|
16
|
+
lib/protobuf/wire_type.rb
|
17
|
+
lib/ruby_protobuf.rb
|
18
|
+
test/addressbook.proto
|
19
|
+
test/addressbook.rb
|
20
|
+
test/data/data.bin
|
21
|
+
test/data/data_source.py
|
22
|
+
test/data/types.bin
|
23
|
+
test/data/types_source.py
|
24
|
+
test/test_addressbook.rb
|
25
|
+
test/test_compiler.rb
|
26
|
+
test/test_message.rb
|
27
|
+
test/test_parse.rb
|
28
|
+
test/test_ruby_protobuf.rb
|
29
|
+
test/test_serialize.rb
|
30
|
+
test/test_types.rb
|
31
|
+
test/types.proto
|
32
|
+
test/types.rb
|
data/README.txt
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
= RubyProtobuf
|
2
|
+
|
3
|
+
* http://code.google.com/p/ruby-protobuf
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Protocol Buffers for Ruby.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Compile .proto file to ruby script
|
12
|
+
* Parse the binary wire format for protocol buffer
|
13
|
+
* Serialize data to the binary wire format for protocol buffer
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
bin/rprotoc -I lib test/addressbook.proto
|
18
|
+
|
19
|
+
== REQUIREMENTS:
|
20
|
+
|
21
|
+
* All you need are included.
|
22
|
+
|
23
|
+
== INSTALL:
|
24
|
+
|
25
|
+
* sudo gem install ruby-protobuf
|
26
|
+
|
27
|
+
== LICENSE:
|
28
|
+
|
29
|
+
(The MIT License)
|
30
|
+
|
31
|
+
Copyright (c) 2008 FIX
|
32
|
+
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
34
|
+
a copy of this software and associated documentation files (the
|
35
|
+
'Software'), to deal in the Software without restriction, including
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
37
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
38
|
+
permit persons to whom the Software is furnished to do so, subject to
|
39
|
+
the following conditions:
|
40
|
+
|
41
|
+
The above copyright notice and this permission notice shall be
|
42
|
+
included in all copies or substantial portions of the Software.
|
43
|
+
|
44
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
45
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
46
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
47
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
48
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
49
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
50
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
$:.push(File.dirname(__FILE__) + '/lib')
|
4
|
+
require 'rubygems'
|
5
|
+
require 'hoe'
|
6
|
+
require 'ruby_protobuf'
|
7
|
+
|
8
|
+
Hoe.new('ruby_protobuf', RubyProtobuf::VERSION) do |p|
|
9
|
+
p.rubyforge_name = 'ruby-protobuf'
|
10
|
+
p.author = 'ANDO Yasushi'
|
11
|
+
p.email = 'andyjpn@gmail.com'
|
12
|
+
p.summary = 'Protocol Buffers for Ruby'
|
13
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
14
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
15
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
# vim: syntax=Ruby
|
data/bin/rprotoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
$: << "#{File.dirname(__FILE__)}/../lib"
|
3
|
+
require 'optparse'
|
4
|
+
require 'ruby_protobuf'
|
5
|
+
|
6
|
+
|
7
|
+
COMMAND_LINE = "#{$0} #{ARGV.join(' ')} PROTO_FILE"
|
8
|
+
OPT = {}
|
9
|
+
opts = OptionParser.new
|
10
|
+
#opts.on('-p', '--proto_path <PATH>', 'Specify the directory in which to search for imports. The current directory is default.'){|v| OPT[:proto_path] = v}
|
11
|
+
opts.on('-o', '--out <OUT_DIR>', 'Specify the directory in which Ruby source file is generated. The current directory is default.'){|v| OPT[:out] = v}
|
12
|
+
opts.on_tail('-v', '--version', 'Show version.'){puts(opts.ver); exit}
|
13
|
+
opts.on_tail('-h', '--help', 'Show this message.'){puts(opts.help); exit}
|
14
|
+
|
15
|
+
::Version = RubyProtobuf::VERSION
|
16
|
+
opts.order! ARGV
|
17
|
+
PROTO_FILE = ARGV.shift
|
18
|
+
|
19
|
+
RubyProtobuf.new.start PROTO_FILE, OPT
|
20
|
+
|
21
|
+
|
data/bin/ruby_protobuf
ADDED
File without changes
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# This is a quite temporary implementation.
|
2
|
+
# I'll create a compiler class using Racc.
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
class Compiler
|
6
|
+
INDENT_UNIT = ' '
|
7
|
+
|
8
|
+
def self.compile(filename)
|
9
|
+
self.new.compile filename
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@indent_level = 0
|
14
|
+
@ret = <<-eos
|
15
|
+
require 'protobuf/message'
|
16
|
+
require 'protobuf/enum'
|
17
|
+
require 'protobuf/service'
|
18
|
+
require 'protobuf/extend'
|
19
|
+
|
20
|
+
eos
|
21
|
+
end
|
22
|
+
|
23
|
+
def indent
|
24
|
+
INDENT_UNIT * @indent_level
|
25
|
+
end
|
26
|
+
|
27
|
+
def puts_with_indent(string)
|
28
|
+
#puts "#{indent}#{string}"
|
29
|
+
@ret += "#{indent}#{string}\n"
|
30
|
+
end
|
31
|
+
alias putswi puts_with_indent
|
32
|
+
|
33
|
+
def compile(filename)
|
34
|
+
File.open filename, 'r' do |file|
|
35
|
+
file.each_line do |line|
|
36
|
+
line.sub! /^(.*)\/\/.*/, '\1'
|
37
|
+
line.strip!
|
38
|
+
case line
|
39
|
+
when /^package\s+(\w+(\.\w+)?)\s*;$/
|
40
|
+
$1.split('.').each do |path|
|
41
|
+
putswi "module #{path.capitalize}"
|
42
|
+
@indent_level += 1
|
43
|
+
end
|
44
|
+
when /^message\s+(\w+)\s*\{$/
|
45
|
+
putswi "class #{$1} < Protobuf::Message"
|
46
|
+
@indent_level += 1
|
47
|
+
when /^(required|optional|repeated)\s+(\w+(\.\w+)?)\s+(\w+)\s*=\s*(\d+)\s*(\[\s*default\s*=\s*(\w+)\s*\])?\s*;$/
|
48
|
+
rule, type, name, tag, default = $1, $2, $4, $5, $7
|
49
|
+
if default
|
50
|
+
default = default =~ /\d+(\.\d+)/ \
|
51
|
+
? ", {:default => #{default}}" \
|
52
|
+
: ", {:default => :#{default}}"
|
53
|
+
end
|
54
|
+
putswi "#{rule} :#{type}, :#{name}, #{tag}#{default}"
|
55
|
+
when /^enum\s+(\w+)\s*\{$/
|
56
|
+
putswi "class #{$1} < Protobuf::Enum"
|
57
|
+
@indent_level += 1
|
58
|
+
when /^(\w+)\s*=\s*(\w+)\s*;$/
|
59
|
+
putswi "#{$1} = #{$2}"
|
60
|
+
when /^extensions\s+(\w+)\s+to\s+(\w+)\s*;/
|
61
|
+
low, high = $1, $2
|
62
|
+
low = 'Protobuf::Extend.MIN' if low == 'min'
|
63
|
+
high = 'Protobuf::Extend.MAX' if high == 'max'
|
64
|
+
putswi "extensions #{min}..#{max}"
|
65
|
+
when /^extend\s+(\w+)\s*\{/
|
66
|
+
putswi "class #{$1} < Protobuf::Extend"
|
67
|
+
@indent_level += 1
|
68
|
+
when /^service\s+(\w+)\s*\{/
|
69
|
+
putswi "class #{$1} < Protobuf::Service"
|
70
|
+
@indent_level += 1
|
71
|
+
when /^rpc\s+(\w+)\s+\(\s*(\w+)\s*\)\s+returns\s+\(\s*(\w+)\s*\)\s*;/
|
72
|
+
putswi "rpc :#{$1} => :#{$2}, :#{$3} => :#{$4}"
|
73
|
+
when /^option\s+(\w+)\s*=\s*(.+)\s*;/
|
74
|
+
putswi "Protobuf::OPTIONS[:#{$1}] = :#{$2}"
|
75
|
+
when /^\}$/
|
76
|
+
@indent_level -= 1
|
77
|
+
putswi "end"
|
78
|
+
when ''
|
79
|
+
putswi ''
|
80
|
+
end
|
81
|
+
end
|
82
|
+
while 0 < @indent_level
|
83
|
+
@indent_level -= 1
|
84
|
+
putswi "end"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
@ret
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'protobuf/wire_type'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
class InvalidWireType < StandardError; end
|
5
|
+
|
6
|
+
class Decoder
|
7
|
+
class <<self
|
8
|
+
def decode(stream, message)
|
9
|
+
self.new(stream, message).decode
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(stream=nil, message=nil)
|
14
|
+
@stream, @message = stream, message
|
15
|
+
end
|
16
|
+
|
17
|
+
def decode(stream=@stream, message=@message)
|
18
|
+
until stream.eof?
|
19
|
+
tag, wire_type = read_key stream
|
20
|
+
bytes =
|
21
|
+
case wire_type
|
22
|
+
when WireType::VARINT
|
23
|
+
read_varint stream
|
24
|
+
when WireType::FIXED64
|
25
|
+
read_fixed64 stream
|
26
|
+
when WireType::LENGTH_DELIMITED
|
27
|
+
read_length_delimited stream
|
28
|
+
when WireType::START_GROUP
|
29
|
+
read_start_group stream
|
30
|
+
when WireType::END_GROUP
|
31
|
+
read_end_group stream
|
32
|
+
when WireType::FIXED32
|
33
|
+
read_fixed32 stream
|
34
|
+
else
|
35
|
+
raise InvalidWireType.new(wire_type)
|
36
|
+
end
|
37
|
+
message.set_field tag, bytes
|
38
|
+
end
|
39
|
+
message
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def read_key(stream)
|
45
|
+
bytes = read_varint stream
|
46
|
+
#TODO 1 < bytes.size のときエラー
|
47
|
+
wire_type = bytes[0] & 0b00000111
|
48
|
+
tag = bytes[0] >> 3 # TODO
|
49
|
+
[tag, wire_type]
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_varint(stream)
|
53
|
+
bytes = []
|
54
|
+
begin
|
55
|
+
byte = stream.readchar
|
56
|
+
bytes << (byte & 0b01111111)
|
57
|
+
end while byte >> 7 == 1
|
58
|
+
bytes
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_fixed64(stream)
|
62
|
+
stream.read(8)
|
63
|
+
end
|
64
|
+
|
65
|
+
def read_length_delimited(stream)
|
66
|
+
bytes = read_varint stream
|
67
|
+
value_length = 0
|
68
|
+
bytes.each_with_index do |byte, index|
|
69
|
+
value_length |= byte << (7 * index)
|
70
|
+
end
|
71
|
+
value = stream.read value_length
|
72
|
+
value.unpack('c*')
|
73
|
+
end
|
74
|
+
|
75
|
+
def read_start_group(stream)
|
76
|
+
raise NotImplementedError.new('Group is duplecated.')
|
77
|
+
end
|
78
|
+
|
79
|
+
def read_end_group(stream)
|
80
|
+
raise NotImplementedError.new('Group is duplecated.')
|
81
|
+
end
|
82
|
+
|
83
|
+
def read_fixed32(stream)
|
84
|
+
stream.read(4)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'protobuf/wire_type'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
class Encoder
|
5
|
+
class <<self
|
6
|
+
def encode(stream, message)
|
7
|
+
self.new(stream, message).encode
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(stream=nil, message=nil)
|
12
|
+
@stream, @message = stream, message
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode(stream=@stream, message=@message)
|
16
|
+
message.each_field do |field, value|
|
17
|
+
key = (field.tag << 3) | field.wire_type
|
18
|
+
key_bytes = Protobuf::Field::Int.get_bytes key
|
19
|
+
#stream.write key_bytes.pack('C*')
|
20
|
+
stream.write key_bytes
|
21
|
+
|
22
|
+
if field.repeated?
|
23
|
+
value.each do |val|
|
24
|
+
bytes = field.get val
|
25
|
+
#stream.write bytes.pack('C*')
|
26
|
+
stream.write bytes
|
27
|
+
end
|
28
|
+
else
|
29
|
+
bytes = field.get value
|
30
|
+
#stream.write bytes.pack('C*')
|
31
|
+
stream.write bytes
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,547 @@
|
|
1
|
+
require 'protobuf/wire_type'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Field
|
5
|
+
def self.build(message_class, rule, type, name, tag, opts={})
|
6
|
+
Base.build message_class, rule, type, name, tag, opts
|
7
|
+
end
|
8
|
+
|
9
|
+
class InvalidRuleError < StandardError; end
|
10
|
+
|
11
|
+
class Base
|
12
|
+
class <<self
|
13
|
+
def build(message_class, rule, type, name, tag, opts={})
|
14
|
+
field_class = nil
|
15
|
+
begin
|
16
|
+
field_class = eval "Protobuf::Field::#{type.to_s.capitalize}Field"
|
17
|
+
rescue NameError
|
18
|
+
type = typename_to_class message_class, type
|
19
|
+
field_class =
|
20
|
+
if type.superclass == Protobuf::Enum
|
21
|
+
Protobuf::Field::Enum
|
22
|
+
elsif type.superclass == Protobuf::Message
|
23
|
+
Protobuf::Field::Message
|
24
|
+
else
|
25
|
+
raise $!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
field_class.new message_class, rule, type, name, tag, opts
|
29
|
+
end
|
30
|
+
|
31
|
+
def typename_to_class(message_class, type)
|
32
|
+
modules = message_class.to_s.split('::')
|
33
|
+
while
|
34
|
+
begin
|
35
|
+
type = eval((modules | [type.to_s]).join('::'))
|
36
|
+
break
|
37
|
+
rescue NameError
|
38
|
+
modules.empty? ? raise($!) : modules.pop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_accessor :message_class, :rule, :type, :name, :tag, :default
|
46
|
+
|
47
|
+
def initialize(message_class, rule, type, name, tag, opts={})
|
48
|
+
@message_class, @rule, @type, @name, @tag, @default =
|
49
|
+
message_class, rule, type, name, tag, opts[:default]
|
50
|
+
@error_message = 'Type invalid'
|
51
|
+
end
|
52
|
+
|
53
|
+
def default_value
|
54
|
+
case rule
|
55
|
+
when :repeated
|
56
|
+
FieldArray.new self
|
57
|
+
when :required, :optional
|
58
|
+
typed_default_value default
|
59
|
+
else
|
60
|
+
raise InvalidRuleError
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def typed_default_value(default=nil)
|
65
|
+
default
|
66
|
+
end
|
67
|
+
|
68
|
+
def define_accessor(message_instance)
|
69
|
+
message_instance.instance_variable_set "@#{name}", default_value
|
70
|
+
define_getter message_instance
|
71
|
+
define_setter message_instance unless rule == :repeated
|
72
|
+
end
|
73
|
+
|
74
|
+
def define_getter(message_instance)
|
75
|
+
message_instance.instance_eval %Q{
|
76
|
+
def #{name}
|
77
|
+
@#{name}
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def define_setter(message_instance)
|
83
|
+
message_instance.instance_eval %Q{
|
84
|
+
def #{name}=(val)
|
85
|
+
field = get_field_by_name #{name.inspect}
|
86
|
+
if field.acceptable? val
|
87
|
+
@#{name} = val
|
88
|
+
end
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def set(message_instance, bytes)
|
94
|
+
if repeated?
|
95
|
+
set_array message_instance, bytes
|
96
|
+
else
|
97
|
+
set_bytes message_instance, bytes
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_array(message_instance, bytes)
|
102
|
+
raise NotImplementedError
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_bytes(message_instance, bytes)
|
106
|
+
raise NotImplementedError
|
107
|
+
end
|
108
|
+
|
109
|
+
def get(value)
|
110
|
+
get_bytes value
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_bytes(value)
|
114
|
+
raise NotImplementedError
|
115
|
+
end
|
116
|
+
|
117
|
+
def merge(message_instance, bytes)
|
118
|
+
if repeated?
|
119
|
+
merge_array method_instance, bytes
|
120
|
+
else
|
121
|
+
merge_value method_instance, bytes
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def merge_array(message_instance, bytes)
|
126
|
+
raise NotImplementedError
|
127
|
+
end
|
128
|
+
|
129
|
+
def merge_value(message_instance, bytes)
|
130
|
+
raise NotImplementedError
|
131
|
+
end
|
132
|
+
|
133
|
+
def repeated?; rule == :repeated end
|
134
|
+
def required?; rule == :required end
|
135
|
+
def optional?; rule == :optional end
|
136
|
+
|
137
|
+
def max; self.class.max end
|
138
|
+
def min; self.class.min end
|
139
|
+
|
140
|
+
def acceptable?(val)
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def error_message
|
145
|
+
@error_message
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_s
|
149
|
+
"#{rule} #{type} #{name} = #{tag} #{default ? "[default=#{default}]" : ''}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class FieldArray < Array
|
154
|
+
def initialize(field)
|
155
|
+
@field = field
|
156
|
+
end
|
157
|
+
|
158
|
+
def []=(nth, val)
|
159
|
+
if @field.acceptable? val
|
160
|
+
super
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def <<(val)
|
165
|
+
if @field.acceptable? val
|
166
|
+
super
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def push(val)
|
171
|
+
if @field.acceptable? val
|
172
|
+
super
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def unshift(val)
|
177
|
+
if @field.acceptable? val
|
178
|
+
super
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def to_s
|
183
|
+
"[#{@field.name}]"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class StringField < Base
|
188
|
+
def wire_type
|
189
|
+
Protobuf::WireType::LENGTH_DELIMITED
|
190
|
+
end
|
191
|
+
|
192
|
+
def typed_default_value(default=nil)
|
193
|
+
default or ''
|
194
|
+
end
|
195
|
+
|
196
|
+
def acceptable?(val)
|
197
|
+
raise TypeError unless val.instance_of? String
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
201
|
+
def set_bytes(method_instance, bytes)
|
202
|
+
method_instance.send("#{name}=", bytes.pack('U*'))
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_bytes(value)
|
206
|
+
bytes = value.unpack('U*')
|
207
|
+
string_size = Int.get_bytes bytes.size
|
208
|
+
#(string_size + bytes).pack('C*')
|
209
|
+
string_size + bytes.pack('C*')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class BytesField < Base
|
214
|
+
def wire_type
|
215
|
+
Protobuf::WireType::VARINT
|
216
|
+
end
|
217
|
+
|
218
|
+
def typed_default_value(default=nil)
|
219
|
+
default or []
|
220
|
+
end
|
221
|
+
|
222
|
+
def set_bytes(method_instance, bytes)
|
223
|
+
method_instance.send("#{name}=", bytes)
|
224
|
+
end
|
225
|
+
|
226
|
+
def get_bytes(value)
|
227
|
+
string_size = Int.get_bytes value.size
|
228
|
+
string_size + value.pack('C*')
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class Int < Base
|
233
|
+
def wire_type
|
234
|
+
Protobuf::WireType::VARINT
|
235
|
+
end
|
236
|
+
|
237
|
+
def typed_default_value(default=nil)
|
238
|
+
default or 0
|
239
|
+
end
|
240
|
+
|
241
|
+
def set_bytes(method_instance, bytes)
|
242
|
+
# TODO should refactor using pack('w*')
|
243
|
+
value = 0
|
244
|
+
bytes.each_with_index do |byte, index|
|
245
|
+
value |= byte << (7 * index)
|
246
|
+
end
|
247
|
+
method_instance.send("#{name}=", value)
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.get_bytes(value)
|
251
|
+
# TODO should refactor using unpack('w*')
|
252
|
+
#return [value].pack('w*').unpack('C*')
|
253
|
+
return [0].pack('C') if value == 0
|
254
|
+
bytes = []
|
255
|
+
until value == 0
|
256
|
+
byte = 0
|
257
|
+
7.times do |i|
|
258
|
+
byte |= (value & 1) << i
|
259
|
+
value >>= 1
|
260
|
+
end
|
261
|
+
byte |= 0b10000000
|
262
|
+
bytes << byte
|
263
|
+
end
|
264
|
+
#bytes[0] &= 0b01111111
|
265
|
+
#bytes
|
266
|
+
bytes[bytes.size - 1] &= 0b01111111
|
267
|
+
bytes.pack('C*')
|
268
|
+
end
|
269
|
+
|
270
|
+
def get_bytes(value)
|
271
|
+
self.class.get_bytes value
|
272
|
+
end
|
273
|
+
|
274
|
+
def acceptable?(val)
|
275
|
+
raise TypeError.new(val.class.name) unless val.is_a? Integer
|
276
|
+
raise RangeError.new(val) if val < min or max < val
|
277
|
+
true
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class Int32Field < Int
|
282
|
+
def self.max; 1.0/0.0 end
|
283
|
+
def self.min; -1.0/0.0 end
|
284
|
+
end
|
285
|
+
|
286
|
+
class Int64Field < Int
|
287
|
+
def self.max; 1.0/0.0 end
|
288
|
+
def self.min; -1.0/0.0 end
|
289
|
+
end
|
290
|
+
|
291
|
+
class Uint32Field < Int
|
292
|
+
def self.max; 1.0/0.0 end
|
293
|
+
def self.min; 0 end
|
294
|
+
end
|
295
|
+
|
296
|
+
class Uint64Field < Int
|
297
|
+
def self.max; 1.0/0.0 end
|
298
|
+
def self.min; 0 end
|
299
|
+
end
|
300
|
+
|
301
|
+
class Sint32Field < Int
|
302
|
+
def self.max; 1.0/0.0 end
|
303
|
+
def self.min; -1.0/0.0 end
|
304
|
+
|
305
|
+
def set_bytes(method_instance, bytes)
|
306
|
+
# TODO use only bit-operations
|
307
|
+
byte = bytes.first
|
308
|
+
value =
|
309
|
+
if byte % 2 == 0
|
310
|
+
byte / 2
|
311
|
+
else
|
312
|
+
-(byte + 1) / 2
|
313
|
+
end
|
314
|
+
method_instance.send("#{name}=", value)
|
315
|
+
end
|
316
|
+
|
317
|
+
def get_bytes(value)
|
318
|
+
#(value << 1) ^ (value >> 31)
|
319
|
+
[(value << 1) ^ (value >> 31)].pack('C*')
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
class Sint64Field < Int
|
324
|
+
def self.max; 1.0/0.0 end
|
325
|
+
def self.min; -1.0/0.0 end
|
326
|
+
|
327
|
+
def set_bytes(method_instance, bytes)
|
328
|
+
# TODO use only bit-operations
|
329
|
+
byte = bytes.first
|
330
|
+
value =
|
331
|
+
if byte % 2 == 0
|
332
|
+
byte / 2
|
333
|
+
else
|
334
|
+
-(byte + 1) / 2
|
335
|
+
end
|
336
|
+
method_instance.send("#{name}=", value)
|
337
|
+
end
|
338
|
+
|
339
|
+
def get_bytes(value)
|
340
|
+
#(value << 1) ^ (value >> 63)
|
341
|
+
[(value << 1) ^ (value >> 63)].pack('C*')
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
class DoubleField < Int
|
346
|
+
def wire_type
|
347
|
+
Protobuf::WireType::FIXED64
|
348
|
+
end
|
349
|
+
|
350
|
+
#TODO
|
351
|
+
def self.max
|
352
|
+
'0x7fefffffffffffff'.unpack('d').first
|
353
|
+
end
|
354
|
+
|
355
|
+
#TODO
|
356
|
+
def self.min
|
357
|
+
-(2**(64/2) - 1)
|
358
|
+
end
|
359
|
+
|
360
|
+
def set_bytes(method_instance, bytes)
|
361
|
+
method_instance.send("#{name}=", bytes.unpack('E').first)
|
362
|
+
end
|
363
|
+
|
364
|
+
def get_bytes(value)
|
365
|
+
[value].pack('E')
|
366
|
+
end
|
367
|
+
|
368
|
+
def acceptable?(val)
|
369
|
+
raise TypeError.new(val.class.name) unless val.is_a? Numeric
|
370
|
+
raise RangeError.new(val) if val < min or max < val
|
371
|
+
true
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
class FloatField < Int
|
376
|
+
def wire_type
|
377
|
+
Protobuf::WireType::FIXED32
|
378
|
+
end
|
379
|
+
|
380
|
+
#TODO
|
381
|
+
def self.max
|
382
|
+
'0x7fefffffffffffff'.unpack('e').first
|
383
|
+
end
|
384
|
+
|
385
|
+
#TODO
|
386
|
+
def self.min
|
387
|
+
-(2**(32/2) - 1)
|
388
|
+
end
|
389
|
+
|
390
|
+
def set_bytes(method_instance, bytes)
|
391
|
+
method_instance.send("#{name}=", bytes.unpack('e').first)
|
392
|
+
end
|
393
|
+
|
394
|
+
def get_bytes(value)
|
395
|
+
[value].pack('e')
|
396
|
+
end
|
397
|
+
|
398
|
+
def acceptable?(val)
|
399
|
+
raise TypeError unless val.is_a? Numeric
|
400
|
+
raise RangeError if val < min or max < val
|
401
|
+
true
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
class Fixed32Field < Int
|
406
|
+
def wire_type
|
407
|
+
Protobuf::WireType::FIXED32
|
408
|
+
end
|
409
|
+
|
410
|
+
def self.max
|
411
|
+
2**32
|
412
|
+
end
|
413
|
+
|
414
|
+
def self.min
|
415
|
+
0
|
416
|
+
end
|
417
|
+
|
418
|
+
def set_bytes(method_instance, bytes)
|
419
|
+
method_instance.send("#{name}=", bytes.unpack('L').first)
|
420
|
+
end
|
421
|
+
|
422
|
+
def get_bytes(value)
|
423
|
+
[value].pack('L')
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
class Fixed64Field < Int
|
428
|
+
def wire_type
|
429
|
+
Protobuf::WireType::FIXED64
|
430
|
+
end
|
431
|
+
|
432
|
+
def self.max
|
433
|
+
2**64
|
434
|
+
end
|
435
|
+
|
436
|
+
def self.min
|
437
|
+
0
|
438
|
+
end
|
439
|
+
|
440
|
+
def set_bytes(method_instance, bytes)
|
441
|
+
method_instance.send("#{name}=", bytes.unpack('l').first)
|
442
|
+
end
|
443
|
+
|
444
|
+
def get_bytes(value)
|
445
|
+
[value].pack('Q')
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
class Sfinxed32Field < Int
|
450
|
+
def wire_type
|
451
|
+
Protobuf::WireType::FIXED32
|
452
|
+
end
|
453
|
+
|
454
|
+
def self.max
|
455
|
+
2**(32/2)
|
456
|
+
end
|
457
|
+
|
458
|
+
def self.min
|
459
|
+
-(2**(32/2) - 1)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
class Sfixed64Field < Int
|
464
|
+
def wire_type
|
465
|
+
Protobuf::WireType::FIXED64
|
466
|
+
end
|
467
|
+
|
468
|
+
def self.max
|
469
|
+
2**(64/2)
|
470
|
+
end
|
471
|
+
|
472
|
+
def self.min
|
473
|
+
-(2**(64/2) - 1)
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
class BoolField < Int
|
478
|
+
def typed_default_value(default=nil)
|
479
|
+
default or false
|
480
|
+
end
|
481
|
+
|
482
|
+
def acceptable?(val)
|
483
|
+
raise TypeError unless [TrueClass, FalseClass].include? val.class
|
484
|
+
true
|
485
|
+
end
|
486
|
+
|
487
|
+
def set_bytes(method_instance, bytes)
|
488
|
+
method_instance.send("#{name}=", bytes.first == 1)
|
489
|
+
end
|
490
|
+
|
491
|
+
def get_bytes(value)
|
492
|
+
[value ? 1 : 0].pack('C')
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
class Message < Base
|
497
|
+
def wire_type
|
498
|
+
Protobuf::WireType::LENGTH_DELIMITED
|
499
|
+
end
|
500
|
+
|
501
|
+
def typed_default_value(default=nil)
|
502
|
+
if default.is_a? Symbol
|
503
|
+
type.module_eval default.to_s
|
504
|
+
else
|
505
|
+
default
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def acceptable?(val)
|
510
|
+
raise TypeError unless val.instance_of? type
|
511
|
+
true
|
512
|
+
end
|
513
|
+
|
514
|
+
def set_bytes(method_instance, bytes)
|
515
|
+
message = type.new
|
516
|
+
#message.parse_from bytes
|
517
|
+
message.parse_from_string bytes.pack('U*') # TODO
|
518
|
+
method_instance.send("#{name}=", message)
|
519
|
+
end
|
520
|
+
|
521
|
+
def set_array(method_instance, bytes)
|
522
|
+
message = type.new
|
523
|
+
#message.parse_from bytes
|
524
|
+
message.parse_from_string bytes.pack('U*')
|
525
|
+
arr = method_instance.send name
|
526
|
+
arr << message
|
527
|
+
end
|
528
|
+
|
529
|
+
def get_bytes(value)
|
530
|
+
stringio = StringIO.new ''
|
531
|
+
value.serialize_to stringio
|
532
|
+
bytes = stringio.string.unpack 'C*'
|
533
|
+
string_size = Int.get_bytes bytes.size
|
534
|
+
#(string_size + bytes).pack('C*')
|
535
|
+
#bytes + string_size
|
536
|
+
string_size + bytes.pack('C*')
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
class Enum < Int
|
541
|
+
def acceptable?(val)
|
542
|
+
raise TypeError unless type.valid_tag? val
|
543
|
+
true
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|