prepor-beefcake 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ require 'beefcake/buffer/encode'
2
+ require 'beefcake/buffer/decode'
@@ -0,0 +1,111 @@
1
+ module Beefcake
2
+
3
+ class Buffer
4
+
5
+ MinUint32 = 0
6
+ MaxUint32 = (1 << 32)-1
7
+ MinInt32 = -(1 << 31)
8
+ MaxInt32 = (1 << 31)-1
9
+
10
+ MinUint64 = 0
11
+ MaxUint64 = (1 << 64)-1
12
+ MinInt64 = -(1 << 63)
13
+ MaxInt64 = (1 << 63)-1
14
+
15
+ WIRES = {
16
+ :int32 => 0,
17
+ :uint32 => 0,
18
+ :sint32 => 0,
19
+ :int64 => 0,
20
+ :uint64 => 0,
21
+ :sint64 => 0,
22
+ :bool => 0,
23
+ :fixed64 => 1,
24
+ :sfixed64 => 1,
25
+ :double => 1,
26
+ :string => 2,
27
+ :bytes => 2,
28
+ :fixed32 => 5,
29
+ :sfixed32 => 5,
30
+ :float => 5,
31
+ }
32
+
33
+ def self.wire_for(type)
34
+ wire = WIRES[type]
35
+
36
+ if wire
37
+ wire
38
+ elsif Class === type && encodable?(type)
39
+ 2
40
+ elsif Module === type
41
+ 0
42
+ else
43
+ raise UnknownType, type
44
+ end
45
+ end
46
+
47
+ def self.encodable?(type)
48
+ return false if ! type.is_a?(Class)
49
+ type.public_method_defined?(:encode)
50
+ end
51
+
52
+ attr_reader :buf
53
+
54
+ alias :to_s :buf
55
+ alias :to_str :buf
56
+
57
+ class OutOfRangeError < StandardError
58
+ def initialize(n)
59
+ super("Value of of range: %d" % [n])
60
+ end
61
+ end
62
+
63
+ class BufferOverflowError < StandardError
64
+ def initialize(s)
65
+ super("Too many bytes read for %s" % [s])
66
+ end
67
+ end
68
+
69
+ class UnknownType < StandardError
70
+ def initialize(s)
71
+ super("Unknown type '%s'" % [s])
72
+ end
73
+ end
74
+
75
+ def initialize(buf="")
76
+ self.buf = buf
77
+ end
78
+
79
+ def buf=(new_buf)
80
+ @buf = new_buf.force_encoding('BINARY')
81
+ @cursor = 0
82
+ end
83
+
84
+ def length
85
+ remain = buf.slice(@cursor..-1)
86
+ remain.bytesize
87
+ end
88
+
89
+ def <<(bytes)
90
+ bytes = bytes.force_encoding('BINARY') if bytes.respond_to? :force_encoding
91
+ buf << bytes
92
+ end
93
+
94
+ def read(n)
95
+ case n
96
+ when Class
97
+ n.decode(read_string)
98
+ when Symbol
99
+ __send__("read_#{n}")
100
+ when Module
101
+ read_uint64
102
+ else
103
+ read_slice = buf.byteslice(@cursor, n)
104
+ @cursor += n
105
+ return read_slice
106
+ end
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,105 @@
1
+ require 'beefcake/buffer/base'
2
+
3
+ module Beefcake
4
+
5
+ class Buffer
6
+
7
+ def read_info
8
+ n = read_uint64
9
+ fn = n >> 3
10
+ wire = n & 0x7
11
+
12
+ [fn, wire]
13
+ end
14
+
15
+ def read_bytes
16
+ read(read_uint64)
17
+ end
18
+
19
+ def read_string
20
+ read_bytes.force_encoding Encoding.find('utf-8')
21
+ end
22
+
23
+ def read_fixed32
24
+ bytes = read(4)
25
+ bytes.unpack("V").first
26
+ end
27
+
28
+ def read_fixed64
29
+ bytes = read(8)
30
+ x, y = bytes.unpack("VV")
31
+ x + (y << 32)
32
+ end
33
+
34
+ def read_int64
35
+ n = read_uint64
36
+ if n > MaxInt64
37
+ n -= (1 << 64)
38
+ end
39
+ n
40
+ end
41
+ alias :read_int32 :read_int64
42
+
43
+ def read_uint64
44
+ n = shift = 0
45
+ while true
46
+ if shift >= 64
47
+ raise BufferOverflowError, "varint"
48
+ end
49
+ b = read(1).ord
50
+
51
+ n |= ((b & 0x7F) << shift)
52
+ shift += 7
53
+ if (b & 0x80) == 0
54
+ return n
55
+ end
56
+ end
57
+ end
58
+ alias :read_uint32 :read_uint64
59
+
60
+ def read_sint64
61
+ decode_zigzag(read_uint64)
62
+ end
63
+ alias :read_sint32 :read_sint64
64
+
65
+ def read_sfixed32
66
+ decode_zigzag(read_fixed32)
67
+ end
68
+
69
+ def read_sfixed64
70
+ decode_zigzag(read_fixed64)
71
+ end
72
+
73
+ def read_float
74
+ bytes = read(4)
75
+ bytes.unpack("e").first
76
+ end
77
+
78
+ def read_double
79
+ bytes = read(8)
80
+ bytes.unpack("E").first
81
+ end
82
+
83
+ def read_bool
84
+ read_int32 != 0
85
+ end
86
+
87
+ def skip(wire)
88
+ case wire
89
+ when 0 then read_uint64
90
+ when 1 then read_fixed64
91
+ when 2 then read_string
92
+ when 5 then read_fixed32
93
+ end
94
+ end
95
+
96
+
97
+ private
98
+
99
+ def decode_zigzag(n)
100
+ (n >> 1) ^ -(n & 1)
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,125 @@
1
+ require 'beefcake/buffer/base'
2
+
3
+ module Beefcake
4
+
5
+ class Buffer
6
+
7
+ def append(type, val, fn)
8
+ if fn != 0
9
+ wire = Buffer.wire_for(type)
10
+ append_info(fn, wire)
11
+ end
12
+
13
+ __send__("append_#{type}", val)
14
+ end
15
+
16
+ def append_info(fn, wire)
17
+ append_uint32((fn << 3) | wire)
18
+ end
19
+
20
+ def append_fixed32(n, tag=false)
21
+ if n < MinUint32 || n > MaxUint32
22
+ raise OutOfRangeError, n
23
+ end
24
+
25
+ self << [n].pack("V")
26
+ end
27
+
28
+ def append_fixed64(n)
29
+ if n < MinUint64 || n > MaxUint64
30
+ raise OutOfRangeError, n
31
+ end
32
+
33
+ self << [n & 0xFFFFFFFF, n >> 32].pack("VV")
34
+ end
35
+
36
+ def append_int32(n)
37
+ if n < MinInt32 || n > MaxInt32
38
+ raise OutOfRangeError, n
39
+ end
40
+
41
+ append_int64(n)
42
+ end
43
+
44
+ def append_uint32(n)
45
+ if n < MinUint32 || n > MaxUint32
46
+ raise OutOfRangeError, n
47
+ end
48
+
49
+ append_uint64(n)
50
+ end
51
+
52
+ def append_int64(n)
53
+ if n < MinInt64 || n > MaxInt64
54
+ raise OutOfRangeError, n
55
+ end
56
+
57
+ if n < 0
58
+ n += (1 << 64)
59
+ end
60
+
61
+ append_uint64(n)
62
+ end
63
+
64
+ def append_sint32(n)
65
+ append_uint32((n << 1) ^ (n >> 31))
66
+ end
67
+
68
+ def append_sfixed32(n)
69
+ append_fixed32((n << 1) ^ (n >> 31))
70
+ end
71
+
72
+ def append_sint64(n)
73
+ append_uint64((n << 1) ^ (n >> 63))
74
+ end
75
+
76
+ def append_sfixed64(n)
77
+ append_fixed64((n << 1) ^ (n >> 63))
78
+ end
79
+
80
+ def append_uint64(n)
81
+ if n < MinUint64 || n > MaxUint64
82
+ raise OutOfRangeError, n
83
+ end
84
+
85
+ while true
86
+ bits = n & 0x7F
87
+ n >>= 7
88
+ if n == 0
89
+ return self << bits
90
+ end
91
+ self << (bits | 0x80)
92
+ end
93
+ end
94
+
95
+ def append_float(n)
96
+ self << [n].pack("e")
97
+ end
98
+
99
+ def append_double(n)
100
+ self << [n].pack("E")
101
+ end
102
+
103
+ def append_bool(n)
104
+ append_int64(n ? 1 : 0)
105
+ end
106
+
107
+ def append_string(s)
108
+ actual_string = thaw_string s
109
+ encoded = actual_string.force_encoding 'binary'
110
+ append_uint64(encoded.length)
111
+ self << encoded
112
+ end
113
+ alias :append_bytes :append_string
114
+
115
+
116
+ private
117
+ def thaw_string(s)
118
+ if s.frozen?
119
+ s = s.dup
120
+ end
121
+ s.to_s
122
+ end
123
+ end
124
+
125
+ end
@@ -0,0 +1,313 @@
1
+ # encoding: ASCII-8BIT
2
+ # The above line allows concatenation of constant strings like ".pb.rb" to
3
+ # maintain the internal format of the buffers, rather than converting the
4
+ # buffer to US-ASCII
5
+
6
+ require 'beefcake'
7
+ require 'stringio'
8
+
9
+ class CodeGeneratorRequest
10
+ include Beefcake::Message
11
+
12
+
13
+ class FieldDescriptorProto
14
+ include Beefcake::Message
15
+
16
+ module Type
17
+ ## 0 is reserved for errors.
18
+ ## Order is weird for historical reasons.
19
+ TYPE_DOUBLE = 1
20
+ TYPE_FLOAT = 2
21
+ TYPE_INT64 = 3 ## Not ZigZag encoded. Negative numbers
22
+ ## take 10 bytes. Use TYPE_SINT64 if negative
23
+ ## values are likely.
24
+ TYPE_UINT64 = 4
25
+ TYPE_INT32 = 5 ## Not ZigZag encoded. Negative numbers
26
+ ## take 10 bytes. Use TYPE_SINT32 if negative
27
+ ## values are likely.
28
+ TYPE_FIXED64 = 6
29
+ TYPE_FIXED32 = 7
30
+ TYPE_BOOL = 8
31
+ TYPE_STRING = 9
32
+ TYPE_GROUP = 10 ## Tag-delimited aggregate.
33
+ TYPE_MESSAGE = 11 ## Length-delimited aggregate.
34
+
35
+ ## New in version 2.
36
+ TYPE_BYTES = 12
37
+ TYPE_UINT32 = 13
38
+ TYPE_ENUM = 14
39
+ TYPE_SFIXED32 = 15
40
+ TYPE_SFIXED64 = 16
41
+ TYPE_SINT32 = 17 ## Uses ZigZag encoding.
42
+ TYPE_SINT64 = 18 ## Uses ZigZag encoding.
43
+ end
44
+
45
+ module Label
46
+ LABEL_OPTIONAL = 1
47
+ LABEL_REQUIRED = 2
48
+ LABEL_REPEATED = 3
49
+ end
50
+
51
+ optional :name, :string, 1
52
+ optional :number, :int32, 3
53
+ optional :label, Label, 4
54
+
55
+ ## If type_name is set, this need not be set. If both this and type_name
56
+ ## are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
57
+ optional :type, Type, 5
58
+
59
+ ## For message and enum types, this is the name of the type. If the name
60
+ ## starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
61
+ ## rules are used to find the type (i.e. first the nested types within this
62
+ ## message are searched, then within the parent, on up to the root
63
+ ## namespace).
64
+ optional :type_name, :string, 6
65
+
66
+ ## For extensions, this is the name of the type being extended. It is
67
+ ## resolved in the same manner as type_name.
68
+ optional :extended, :string, 2
69
+
70
+ ## For numeric types, contains the original text representation of the value.
71
+ ## For booleans, "true" or "false".
72
+ ## For strings, contains the default text contents (not escaped in any way).
73
+ ## For bytes, contains the C escaped value. All bytes >= 128 are escaped.
74
+ optional :default_value, :string, 7
75
+ end
76
+
77
+
78
+ class EnumValueDescriptorProto
79
+ include Beefcake::Message
80
+
81
+ optional :name, :string, 1
82
+ optional :number, :int32, 2
83
+ # optional EnumValueOptions options = 3;
84
+ end
85
+
86
+ class EnumDescriptorProto
87
+ include Beefcake::Message
88
+
89
+ optional :name, :string, 1
90
+ repeated :value, EnumValueDescriptorProto, 2
91
+ # optional :options, EnumOptions, 3
92
+ end
93
+
94
+ class DescriptorProto
95
+ include Beefcake::Message
96
+
97
+ optional :name, :string, 1
98
+
99
+ repeated :field, FieldDescriptorProto, 2
100
+ repeated :extended, FieldDescriptorProto, 6
101
+ repeated :nested_type, DescriptorProto, 3
102
+ repeated :enum_type, EnumDescriptorProto, 4
103
+ end
104
+
105
+
106
+ class FileDescriptorProto
107
+ include Beefcake::Message
108
+
109
+ optional :name, :string, 1 # file name, relative to root of source tree
110
+ optional :package, :string, 2 # e.g. "foo", "foo.bar", etc.
111
+
112
+ repeated :message_type, DescriptorProto, 4;
113
+ repeated :enum_type, EnumDescriptorProto, 5;
114
+ end
115
+
116
+
117
+ repeated :file_to_generate, :string, 1
118
+ optional :parameter, :string, 2
119
+
120
+ repeated :proto_file, FileDescriptorProto, 15
121
+ end
122
+
123
+ class CodeGeneratorResponse
124
+ include Beefcake::Message
125
+
126
+ class File
127
+ include Beefcake::Message
128
+
129
+ optional :name, :string, 1
130
+ optional :content, :string, 15
131
+ end
132
+
133
+ repeated :file, File, 15
134
+ end
135
+
136
+ module Beefcake
137
+ class Generator
138
+
139
+ L = CodeGeneratorRequest::FieldDescriptorProto::Label
140
+ T = CodeGeneratorRequest::FieldDescriptorProto::Type
141
+
142
+
143
+ def self.compile(ns, req)
144
+ file = req.proto_file.map do |file|
145
+ g = new(StringIO.new)
146
+ g.compile(ns, file)
147
+
148
+ g.c.rewind
149
+ CodeGeneratorResponse::File.new(
150
+ :name => File.basename(file.name, ".proto") + ".pb.rb",
151
+ :content => g.c.read
152
+ )
153
+ end
154
+
155
+ CodeGeneratorResponse.new(:file => file)
156
+ end
157
+
158
+ attr_reader :c
159
+
160
+ def initialize(c)
161
+ @c = c
162
+ @n = 0
163
+ end
164
+
165
+ def indent(&blk)
166
+ @n += 1
167
+ blk.call
168
+ @n -= 1
169
+ end
170
+
171
+ def indent!(n)
172
+ @n = n
173
+ end
174
+
175
+ def define!(mt)
176
+ puts
177
+ puts "class #{mt.name}"
178
+
179
+ indent do
180
+ puts "include Beefcake::Message"
181
+
182
+ ## Enum Types
183
+ Array(mt.enum_type).each do |et|
184
+ enum!(et)
185
+ end
186
+
187
+ ## Nested Types
188
+ Array(mt.nested_type).each do |nt|
189
+ define!(nt)
190
+ end
191
+ end
192
+ puts "end"
193
+ end
194
+
195
+ def message!(pkg, mt)
196
+ puts
197
+ puts "class #{mt.name}"
198
+
199
+ indent do
200
+ ## Generate Types
201
+ Array(mt.nested_type).each do |nt|
202
+ message!(pkg, nt)
203
+ end
204
+
205
+ ## Generate Fields
206
+ Array(mt.field).each do |f|
207
+ field!(pkg, f)
208
+ end
209
+ end
210
+
211
+ puts "end"
212
+ end
213
+
214
+ def enum!(et)
215
+ puts
216
+ puts "module #{et.name}"
217
+ indent do
218
+ et.value.each do |v|
219
+ puts "%s = %d" % [v.name, v.number]
220
+ end
221
+ end
222
+ puts "end"
223
+ end
224
+
225
+ def field!(pkg, f)
226
+ # Turn the label into Ruby
227
+ label = name_for(f, L, f.label)
228
+
229
+ # Turn the name into a Ruby
230
+ name = ":#{f.name}"
231
+
232
+ # Determine the type-name and convert to Ruby
233
+ type = if f.type_name
234
+ t = f.type_name.gsub(/^\.*/, "").split('.').map { |v| camelize(v) } * '::'
235
+ else
236
+ ":#{name_for(f, T, f.type)}"
237
+ end
238
+
239
+ # Finally, generate the declaration
240
+ out = "%s %s, %s, %d" % [label, name, type, f.number]
241
+
242
+ if f.default_value
243
+ v = case f.type
244
+ when T::TYPE_ENUM
245
+ "%s::%s" % [type, f.default_value]
246
+ when T::TYPE_STRING, T::TYPE_BYTES
247
+ '"%s"' % [f.default_value.gsub('"', '\"')]
248
+ else
249
+ f.default_value
250
+ end
251
+
252
+ out += ", :default => #{v}"
253
+ end
254
+
255
+ puts out
256
+ end
257
+
258
+ # Determines the name for a
259
+ def name_for(b, mod, val)
260
+ b.name_for(mod, val).to_s.gsub(/.*_/, "").downcase
261
+ end
262
+
263
+ def compile(file)
264
+ package_part = file.package ? "for #{file.package}" : ''
265
+ puts "## Generated from #{file.name} #{package_part}".strip
266
+ puts "require \"beefcake\""
267
+ puts
268
+
269
+ ns!(package.split('.').map { |v| camelize(v) }) do
270
+ Array(file.enum_type).each do |et|
271
+ enum!(et)
272
+ end
273
+
274
+ file.message_type.each do |mt|
275
+ define! mt
276
+ end
277
+
278
+ file.message_type.each do |mt|
279
+ message!(file.package, mt)
280
+ end
281
+ end
282
+ end
283
+
284
+ def ns!(modules, &blk)
285
+ if modules.empty?
286
+ blk.call
287
+ else
288
+ puts "module #{modules.first}"
289
+ indent do
290
+ ns!(modules[1..-1], &blk)
291
+ end
292
+ puts "end"
293
+ end
294
+ end
295
+
296
+ def puts(msg=nil)
297
+ if msg
298
+ c.puts((" " * @n) + msg)
299
+ else
300
+ c.puts
301
+ end
302
+ end
303
+
304
+ def camelize(term)
305
+ string = term.to_s
306
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
307
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
308
+ string.gsub!('/', '::')
309
+ string
310
+ end
311
+
312
+ end
313
+ end