prepor-beefcake 1.0.0

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.
@@ -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