bare-rb 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/bare-rb.rb +52 -10
- data/lib/exceptions.rb +30 -0
- data/lib/generative_testing/gen.rb +26 -0
- data/lib/generative_testing/grammar_util.rb +22 -0
- data/lib/generative_testing/monkey_patch.rb +262 -0
- data/lib/lexer.rb +17 -16
- data/lib/parser.rb +66 -18
- data/lib/types.rb +544 -254
- metadata +8 -5
data/lib/types.rb
CHANGED
@@ -3,201 +3,214 @@ require_relative './exceptions'
|
|
3
3
|
class BareTypes
|
4
4
|
|
5
5
|
class BaseType
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# Types which are always equivalent to another instantiation of themselves
|
10
|
-
# Eg. Uint.new == Uint.new
|
11
|
-
# But Union.new(types1) != Union.new(types2)
|
12
|
-
# since unions could have different sets of types
|
13
|
-
def ==(other)
|
14
|
-
self.class == other.class
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class Int < BarePrimitive
|
19
|
-
# https://developers.google.com/protocol-buffers/docs/encoding
|
20
|
-
# Easy to just convert to signed and re-use uint code
|
21
|
-
def encode(msg)
|
22
|
-
mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
|
23
|
-
return Uint.new.encode(mappedInteger)
|
6
|
+
def initialize
|
7
|
+
@finalized = false
|
8
|
+
super
|
24
9
|
end
|
25
|
-
def
|
26
|
-
output = Uint.new.decode(msg)
|
27
|
-
unmapped = output[:value]
|
28
|
-
unmapped = unmapped.odd? ? (unmapped + 1) / - 2 : unmapped / 2
|
29
|
-
return { value: unmapped, rest: output[:rest] }
|
10
|
+
def cycle_search(seen)
|
30
11
|
end
|
31
12
|
end
|
32
13
|
|
33
|
-
class
|
34
|
-
|
35
|
-
|
14
|
+
class Schema
|
15
|
+
attr_accessor :types
|
16
|
+
|
17
|
+
def initialize(types)
|
18
|
+
@types = types.map { |k, v| [k.to_sym, v] }.to_h
|
19
|
+
@types.each do |k, v|
|
20
|
+
unless k.is_a?(Symbol)
|
21
|
+
raise("Keys to a schema must be symbols")
|
22
|
+
end
|
23
|
+
if v.nil?
|
24
|
+
raise("Schema values cannot be nil")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Resolve references in schema
|
29
|
+
# type A u8
|
30
|
+
# type B A
|
31
|
+
# type C B
|
32
|
+
# first loop would find B and make it a reference to A
|
33
|
+
# second loop would find C and make it a reference to B
|
34
|
+
progress = true
|
35
|
+
remaining = @types.keys.to_a
|
36
|
+
while progress
|
37
|
+
progress = false
|
38
|
+
remaining.each do |key|
|
39
|
+
val = @types[key]
|
40
|
+
if val.is_a?(Symbol) && !@types[val].is_a?(Symbol)
|
41
|
+
@types[key.to_sym] = BareTypes::Reference.new(key, @types[val])
|
42
|
+
progress = true
|
43
|
+
else
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@types.each do |key, val|
|
49
|
+
if val.is_a?(Symbol)
|
50
|
+
raise ReferenceException.new("Your types contain an unresolved reference '#{val}'.")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
@types.values.each do |val|
|
55
|
+
val.finalize_references(@types)
|
56
|
+
end
|
57
|
+
|
58
|
+
@types.each do |key, val|
|
59
|
+
val.cycle_search(SeenList.new)
|
60
|
+
end
|
36
61
|
end
|
37
|
-
|
38
|
-
|
62
|
+
|
63
|
+
def ==(otherSchema)
|
64
|
+
return false unless otherSchema.is_a?(BareTypes::Schema)
|
65
|
+
@types == otherSchema.types
|
39
66
|
end
|
40
|
-
end
|
41
67
|
|
42
|
-
|
43
|
-
|
44
|
-
|
68
|
+
def to_s
|
69
|
+
buffer = ""
|
70
|
+
@types.each do |name, type|
|
71
|
+
if type.is_a?(BareTypes::Enum)
|
72
|
+
buffer << "enum #{name} "
|
73
|
+
type.to_schema(buffer)
|
74
|
+
buffer << "\n"
|
75
|
+
else
|
76
|
+
buffer << "type #{name} "
|
77
|
+
type.to_schema(buffer)
|
78
|
+
buffer << "\n"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
buffer
|
45
82
|
end
|
46
|
-
|
47
|
-
|
83
|
+
|
84
|
+
def [](key)
|
85
|
+
return @types[key]
|
48
86
|
end
|
49
87
|
end
|
50
88
|
|
51
|
-
|
52
|
-
|
53
|
-
|
89
|
+
# Used to represent a Type reference in a schema.
|
90
|
+
# eg. test8.schema's address field on Customer contains 'Address'
|
91
|
+
# a reference to the Address type defined earlier.
|
92
|
+
class Reference < BaseType
|
93
|
+
attr_accessor :name
|
94
|
+
attr_accessor :ref
|
95
|
+
|
96
|
+
def cycle_search(seen)
|
97
|
+
seen.add(self)
|
98
|
+
@ref.cycle_search(seen)
|
99
|
+
seen.pop
|
54
100
|
end
|
55
|
-
|
56
|
-
|
101
|
+
|
102
|
+
def ==(other)
|
103
|
+
other.is_a?(Reference) && @name == other.name && @ref == other.ref
|
57
104
|
end
|
58
|
-
end
|
59
105
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
raise error.class, "Unable to convert string to UTF-8=, BARE strings are encoded as UTF8. If you can't convert your string to UTF-8 you can encode it with binary data"
|
106
|
+
def initialize(name, reference)
|
107
|
+
@name = name
|
108
|
+
@ref = reference
|
109
|
+
@finalized = false
|
110
|
+
unless reference.is_a?(BareTypes::BaseType)
|
111
|
+
raise ReferenceException.new("Reference must be to bare types")
|
67
112
|
end
|
68
|
-
bytes = Uint.new.encode(encodedString.size)
|
69
|
-
bytes << encodedString
|
70
|
-
return bytes
|
71
113
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
114
|
+
|
115
|
+
def finalize_references(schema)
|
116
|
+
return if @finalized
|
117
|
+
@finalized = true
|
118
|
+
self.ref.finalize_references(schema)
|
77
119
|
end
|
78
|
-
end
|
79
120
|
|
80
|
-
|
81
|
-
|
82
|
-
return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
|
121
|
+
def encode(msg, buffer)
|
122
|
+
@ref.encode(msg, buffer)
|
83
123
|
end
|
84
124
|
|
85
|
-
def
|
86
|
-
@
|
125
|
+
def decode(msg)
|
126
|
+
@ref.decode(msg)
|
87
127
|
end
|
88
128
|
|
89
|
-
def
|
90
|
-
|
91
|
-
@optionalType = optionalType
|
129
|
+
def to_schema(buffer)
|
130
|
+
buffer << @name.to_s
|
92
131
|
end
|
132
|
+
end
|
93
133
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
134
|
+
class BarePrimitive < BaseType
|
135
|
+
|
136
|
+
# Types which are always equivalent to another instantiation of themselves
|
137
|
+
# Eg. Uint.new == Uint.new
|
138
|
+
# But Union.new(types1) != Union.new(types2)
|
139
|
+
# since unions could have different sets of types
|
140
|
+
|
141
|
+
def ==(other)
|
142
|
+
self.class == other.class
|
102
143
|
end
|
103
144
|
|
104
|
-
def
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
return @optionalType.decode(msg[1..msg.size])
|
109
|
-
end
|
145
|
+
def finalize_references(schema) end
|
146
|
+
|
147
|
+
def to_schema(buffer)
|
148
|
+
buffer << self.class.name.split('::').last.downcase
|
110
149
|
end
|
150
|
+
|
111
151
|
end
|
112
152
|
|
113
|
-
|
114
|
-
|
115
|
-
|
153
|
+
#region Primitives
|
154
|
+
class Int < BarePrimitive
|
155
|
+
# https://developers.google.com/protocol-buffers/docs/encoding
|
156
|
+
# Easy to just convert to signed and re-use uint code
|
157
|
+
def encode(msg, buffer)
|
158
|
+
mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
|
159
|
+
Uint.new.encode(mappedInteger, buffer)
|
116
160
|
end
|
117
161
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
@to = toType
|
162
|
+
def decode(msg)
|
163
|
+
value, rest = Uint.new.decode(msg)
|
164
|
+
value = value.odd? ? (value + 1) / -2 : value / 2
|
165
|
+
return value, rest
|
123
166
|
end
|
167
|
+
end
|
124
168
|
|
125
|
-
|
126
|
-
|
169
|
+
class Void < BarePrimitive
|
170
|
+
def encode(msg, buffer)
|
171
|
+
buffer << "".b
|
127
172
|
end
|
128
173
|
|
129
|
-
def
|
130
|
-
|
174
|
+
def decode(msg)
|
175
|
+
return nil, msg
|
131
176
|
end
|
177
|
+
end
|
132
178
|
|
133
|
-
|
134
|
-
|
135
|
-
msg.
|
136
|
-
bytes << @from.encode(from)
|
137
|
-
bytes << @to.encode(to)
|
138
|
-
end
|
139
|
-
return bytes
|
179
|
+
class F32 < BarePrimitive
|
180
|
+
def encode(msg, buffer)
|
181
|
+
buffer << [msg].pack("e")
|
140
182
|
end
|
141
183
|
|
142
184
|
def decode(msg)
|
143
|
-
|
144
|
-
output = Uint.new.decode(msg)
|
145
|
-
mapSize = output[:value]
|
146
|
-
(mapSize - 1).to_i.downto(0) do
|
147
|
-
output = @from.decode(output[:rest])
|
148
|
-
key = output[:value]
|
149
|
-
output = @to.decode(output[:rest])
|
150
|
-
hash[key] = output[:value]
|
151
|
-
end
|
152
|
-
return {value: hash, rest: output[:rest]}
|
185
|
+
return msg.unpack("e")[0], msg[4..msg.size]
|
153
186
|
end
|
154
187
|
end
|
155
188
|
|
156
|
-
class
|
157
|
-
def
|
158
|
-
|
159
|
-
end
|
160
|
-
|
161
|
-
def ==(otherType)
|
162
|
-
return false unless otherType.is_a?(BareTypes::Union)
|
163
|
-
@intToType.each do |int, type|
|
164
|
-
return false unless type == otherType.intToType[int]
|
165
|
-
end
|
166
|
-
return true
|
189
|
+
class F64 < BarePrimitive
|
190
|
+
def encode(msg, buffer)
|
191
|
+
buffer << [msg].pack("E")
|
167
192
|
end
|
168
193
|
|
169
|
-
def
|
170
|
-
|
171
|
-
raise MinimumSizeError("Union's integer representations must be > 0, instead got: #{i}") if i < 0 or !i.is_a?(Integer)
|
172
|
-
end
|
173
|
-
raise MinimumSizeError("Union must have at least one type") if intToType.keys.size < 1
|
174
|
-
@intToType = intToType
|
194
|
+
def decode(msg)
|
195
|
+
return msg.unpack("E")[0], msg[8..msg.size]
|
175
196
|
end
|
197
|
+
end
|
176
198
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
if type.class == typ.class
|
184
|
-
unionTypeInt = int
|
185
|
-
unionType = typ
|
186
|
-
break
|
187
|
-
end
|
199
|
+
class String < BarePrimitive
|
200
|
+
def encode(msg, buffer)
|
201
|
+
begin
|
202
|
+
encodedString = msg.encode("UTF-8").b
|
203
|
+
rescue Encoding::UndefinedConversionError => error
|
204
|
+
raise error.class, "Unable to convert string to UTF-8=, BARE strings are encoded as UTF8. If you can't convert your string to UTF-8 you can encode it with binary data"
|
188
205
|
end
|
189
|
-
|
190
|
-
|
191
|
-
encoded = unionType.encode(value)
|
192
|
-
bytes << encoded
|
206
|
+
Uint.new.encode(encodedString.size, buffer)
|
207
|
+
buffer << encodedString
|
193
208
|
end
|
194
209
|
|
195
210
|
def decode(msg)
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
value = type.decode(unionTypeInt[:rest])
|
200
|
-
return {value: {value: value[:value], type: type}, rest: value[:rest]}
|
211
|
+
strLen, rest = Uint.new.decode(msg)
|
212
|
+
string = rest[0..strLen - 1]
|
213
|
+
return string.force_encoding("utf-8"), rest[strLen..rest.size]
|
201
214
|
end
|
202
215
|
end
|
203
216
|
|
@@ -206,41 +219,53 @@ class BareTypes
|
|
206
219
|
return otherType.class == BareTypes::DataFixedLen && otherType.length == self.length
|
207
220
|
end
|
208
221
|
|
222
|
+
def to_schema(buffer)
|
223
|
+
buffer << "data<#{@length}>"
|
224
|
+
end
|
225
|
+
|
209
226
|
def length
|
210
|
-
|
227
|
+
@length
|
211
228
|
end
|
212
229
|
|
230
|
+
def finalize_references(schema) end
|
231
|
+
|
213
232
|
def initialize(length)
|
214
|
-
raise MinimumSizeError("DataFixedLen must have a length greater than 0, got: #{length.inspect}") if length < 1
|
233
|
+
raise MinimumSizeError.new("DataFixedLen must have a length greater than 0, got: #{length.inspect}") if length < 1
|
215
234
|
@length = length
|
216
235
|
end
|
217
236
|
|
218
|
-
def encode(msg)
|
219
|
-
|
237
|
+
def encode(msg, buffer)
|
238
|
+
if msg.size != @length
|
239
|
+
raise FixedDataSizeWrong.new("Message is not proper sized for DataFixedLen should have been #{@length} but was #{msg.size}")
|
240
|
+
end
|
241
|
+
buffer << msg
|
220
242
|
end
|
221
243
|
|
222
244
|
def decode(msg)
|
223
|
-
return
|
245
|
+
return msg[0..@length-1], msg[@length..msg.size]
|
224
246
|
end
|
225
247
|
end
|
226
248
|
|
227
249
|
class Data < BarePrimitive
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
250
|
+
|
251
|
+
def finalize_references(schema) end
|
252
|
+
|
253
|
+
def encode(msg, buffer)
|
254
|
+
Uint.new.encode(msg.size, buffer)
|
255
|
+
buffer << msg
|
232
256
|
end
|
233
257
|
|
234
258
|
def decode(msg)
|
235
|
-
|
236
|
-
rest
|
237
|
-
dataSize = output[:value]
|
238
|
-
return {value: rest[0..dataSize-1], rest: rest[dataSize..]}
|
259
|
+
dataSize, rest = Uint.new.decode(msg)
|
260
|
+
return rest[0..dataSize - 1], rest[dataSize..rest.size]
|
239
261
|
end
|
240
262
|
end
|
241
263
|
|
242
264
|
class Uint < BarePrimitive
|
243
|
-
|
265
|
+
|
266
|
+
def finalize_references(schema) end
|
267
|
+
|
268
|
+
def encode(msg, buffer)
|
244
269
|
bytes = "".b
|
245
270
|
_get_next_7_bits_as_byte(msg, 128) do |byte|
|
246
271
|
bytes << byte
|
@@ -253,12 +278,12 @@ class BareTypes
|
|
253
278
|
end
|
254
279
|
end
|
255
280
|
bytes[bytes.size - 1] = [bytes.bytes[bytes.size - 1] & 127].pack('C')[0]
|
256
|
-
raise MaximumSizeError("Maximum u/int allowed is 64 bit precision") if bytes.size > 9
|
257
|
-
|
281
|
+
raise MaximumSizeError.new("Maximum u/int allowed is 64 bit precision") if bytes.size > 9
|
282
|
+
buffer << bytes
|
258
283
|
end
|
259
284
|
|
260
285
|
def decode(msg)
|
261
|
-
ints = msg.unpack("
|
286
|
+
ints = msg.unpack("CCCCCCCC")
|
262
287
|
relevantInts = []
|
263
288
|
i = 0
|
264
289
|
while ints[i] & 0b10000000 == 128
|
@@ -270,220 +295,478 @@ class BareTypes
|
|
270
295
|
relevantInts.each_with_index do |int, idx|
|
271
296
|
sum += int << (idx * 7)
|
272
297
|
end
|
273
|
-
return
|
298
|
+
return sum, msg[(i + 1)..msg.size]
|
274
299
|
end
|
275
300
|
end
|
276
301
|
|
277
302
|
class U8 < BarePrimitive
|
278
|
-
def encode(msg)
|
279
|
-
|
303
|
+
def encode(msg, buffer)
|
304
|
+
buffer << [msg].pack("C")
|
280
305
|
end
|
281
306
|
|
282
307
|
def decode(msg)
|
283
|
-
return
|
308
|
+
return msg[0].unpack("C")[0], msg[1..msg.size]
|
284
309
|
end
|
285
310
|
end
|
286
311
|
|
287
312
|
class U16 < BarePrimitive
|
288
|
-
def encode(msg)
|
289
|
-
|
313
|
+
def encode(msg, buffer)
|
314
|
+
buffer << [msg].pack("v")
|
290
315
|
end
|
291
316
|
|
292
317
|
def decode(msg)
|
293
|
-
return
|
318
|
+
return msg.unpack("v")[0], msg[2..msg.size]
|
294
319
|
end
|
295
320
|
end
|
296
321
|
|
297
322
|
class U32 < BarePrimitive
|
298
|
-
def encode(msg)
|
299
|
-
|
323
|
+
def encode(msg, buffer)
|
324
|
+
buffer << [msg].pack("V")
|
300
325
|
end
|
301
326
|
|
302
327
|
def decode(msg)
|
303
|
-
return
|
328
|
+
return msg.unpack("V")[0], msg[4..msg.size]
|
304
329
|
end
|
305
330
|
end
|
306
331
|
|
307
332
|
class U64 < BarePrimitive
|
308
|
-
def encode(msg)
|
309
|
-
|
333
|
+
def encode(msg, buffer)
|
334
|
+
buffer << [msg].pack("Q")
|
310
335
|
end
|
311
336
|
|
312
337
|
def decode(msg)
|
313
|
-
return
|
338
|
+
return msg.unpack("Q")[0], msg[8..msg.size]
|
314
339
|
end
|
315
340
|
end
|
316
341
|
|
317
342
|
class I8 < BarePrimitive
|
318
|
-
def encode(msg)
|
319
|
-
|
343
|
+
def encode(msg, buffer)
|
344
|
+
buffer << [msg].pack("c")
|
320
345
|
end
|
321
346
|
|
322
347
|
def decode(msg)
|
323
|
-
return
|
348
|
+
return msg[0].unpack("c")[0], msg[1..msg.size]
|
324
349
|
end
|
325
350
|
end
|
326
351
|
|
327
352
|
class I16 < BarePrimitive
|
328
|
-
def encode(msg)
|
329
|
-
|
353
|
+
def encode(msg, buffer)
|
354
|
+
buffer << [msg].pack("s<")
|
330
355
|
end
|
331
356
|
|
332
357
|
def decode(msg)
|
333
|
-
return
|
358
|
+
return msg.unpack('s<')[0], msg[2..msg.size]
|
334
359
|
end
|
335
360
|
end
|
336
361
|
|
337
362
|
class I32 < BarePrimitive
|
338
|
-
def encode(msg)
|
339
|
-
|
363
|
+
def encode(msg, buffer)
|
364
|
+
buffer << [msg].pack("l<")
|
340
365
|
end
|
341
366
|
|
342
367
|
def decode(msg)
|
343
|
-
return
|
368
|
+
return msg.unpack('l<')[0], msg[4..msg.size]
|
344
369
|
end
|
345
370
|
end
|
346
371
|
|
347
372
|
class I64 < BarePrimitive
|
348
|
-
def encode(msg)
|
349
|
-
|
373
|
+
def encode(msg, buffer)
|
374
|
+
buffer << [msg].pack("q<")
|
350
375
|
end
|
351
376
|
|
352
377
|
def decode(msg)
|
353
|
-
return
|
378
|
+
return msg.unpack('q<')[0], msg[8..msg.size]
|
354
379
|
end
|
355
380
|
end
|
356
381
|
|
357
382
|
class Bool < BarePrimitive
|
358
|
-
def encode(msg)
|
359
|
-
|
383
|
+
def encode(msg, buffer)
|
384
|
+
buffer << (msg ? "\x00".b : "\x01".b)
|
385
|
+
end
|
386
|
+
|
387
|
+
def decode(msg)
|
388
|
+
if msg != "\x00" && msg != "\x01"
|
389
|
+
raise InvalidBool.new("Expected a bool but found #{msg.inspect}. Standard requires bool to be 0x00 or 0x01")
|
390
|
+
end
|
391
|
+
return (msg == "\x00" ? true : false), msg[1..msg.size]
|
392
|
+
end
|
393
|
+
end
|
394
|
+
#endregion
|
395
|
+
|
396
|
+
class Optional < BaseType
|
397
|
+
def ==(otherType)
|
398
|
+
return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
|
399
|
+
end
|
400
|
+
|
401
|
+
def to_schema(buffer)
|
402
|
+
buffer << "optional<"
|
403
|
+
@optionalType.to_schema(buffer)
|
404
|
+
buffer << ">"
|
405
|
+
end
|
406
|
+
|
407
|
+
def finalize_references(schema)
|
408
|
+
return if @finalized
|
409
|
+
@finalized = true
|
410
|
+
if @optionalType.is_a?(Symbol)
|
411
|
+
@optionalType = Reference.new(@optionalType, schema[@optionalType])
|
412
|
+
else
|
413
|
+
@optionalType.finalize_references(schema)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def optionalType
|
418
|
+
@optionalType
|
419
|
+
end
|
420
|
+
|
421
|
+
def initialize(optionalType)
|
422
|
+
raise VoidUsedOutsideTaggedSet() if optionalType.class == BareTypes::Void
|
423
|
+
@optionalType = optionalType
|
424
|
+
end
|
425
|
+
|
426
|
+
def encode(msg, buffer)
|
427
|
+
if msg.nil?
|
428
|
+
buffer << "\x00".b
|
429
|
+
else
|
430
|
+
buffer << "\x01".b
|
431
|
+
@optionalType.encode(msg, buffer)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def decode(msg)
|
436
|
+
if msg.unpack("C")[0] == 0
|
437
|
+
return nil, msg[1..msg.size]
|
438
|
+
else
|
439
|
+
return @optionalType.decode(msg[1..msg.size])
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
class Map < BaseType
|
445
|
+
def ==(otherType)
|
446
|
+
return otherType.class == BareTypes::Map && otherType.from == @from && otherType.to == @to
|
447
|
+
end
|
448
|
+
|
449
|
+
def to_schema(buffer)
|
450
|
+
buffer << "map["
|
451
|
+
@from.to_schema(buffer)
|
452
|
+
buffer << "]"
|
453
|
+
@to.to_schema(buffer)
|
454
|
+
end
|
455
|
+
|
456
|
+
def finalize_references(schema)
|
457
|
+
return if @finalized
|
458
|
+
@finalized = true
|
459
|
+
if @from.is_a?(Symbol)
|
460
|
+
@to = Reference.new(@from, schema[@to])
|
461
|
+
else
|
462
|
+
@to.finalize_references(schema)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def initialize(fromType, toType)
|
467
|
+
raise VoidUsedOutsideTaggedSet if fromType.class == BareTypes::Void or toType.class == BareTypes::Void
|
468
|
+
if !fromType.class.ancestors.include?(BarePrimitive) ||
|
469
|
+
fromType.is_a?(BareTypes::Data) ||
|
470
|
+
fromType.is_a?(BareTypes::DataFixedLen)
|
471
|
+
raise MapKeyError("Map keys must use a primitive type which is not data or data<length>.")
|
472
|
+
end
|
473
|
+
@from = fromType
|
474
|
+
@to = toType
|
475
|
+
end
|
476
|
+
|
477
|
+
def from
|
478
|
+
@from
|
479
|
+
end
|
480
|
+
|
481
|
+
def to
|
482
|
+
@to
|
483
|
+
end
|
484
|
+
|
485
|
+
def encode(msg, buffer)
|
486
|
+
Uint.new.encode(msg.size, buffer)
|
487
|
+
msg.each do |from, to|
|
488
|
+
@from.encode(from, buffer)
|
489
|
+
@to.encode(to, buffer)
|
490
|
+
end
|
360
491
|
end
|
361
492
|
|
362
493
|
def decode(msg)
|
363
|
-
|
494
|
+
hash = Hash.new
|
495
|
+
mapSize, rest = Uint.new.decode(msg)
|
496
|
+
# (0..mapSize).each do
|
497
|
+
(mapSize - 1).to_i.downto(0) do
|
498
|
+
key, rest = @from.decode(rest)
|
499
|
+
value, rest = @to.decode(rest)
|
500
|
+
hash[key] = value
|
501
|
+
end
|
502
|
+
return hash, rest
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
class Union < BaseType
|
507
|
+
attr_accessor :intToType
|
508
|
+
|
509
|
+
def cycle_search(seen)
|
510
|
+
if @intToType.size == 1
|
511
|
+
seen.add(self)
|
512
|
+
@intToType.values.each do |type|
|
513
|
+
type.cycle_search(seen)
|
514
|
+
end
|
515
|
+
seen.pop
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def finalize_references(schema)
|
520
|
+
return if @finalized
|
521
|
+
@finalized = true
|
522
|
+
@intToType.keys.each do |key|
|
523
|
+
if @intToType[key].is_a?(Symbol)
|
524
|
+
@intToType[key] = Reference.new(@intToType[key], schema[@intToType[key]])
|
525
|
+
else
|
526
|
+
@intToType[key].finalize_references(schema)
|
527
|
+
end
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def ==(otherType)
|
532
|
+
return false unless otherType.is_a?(BareTypes::Union)
|
533
|
+
@intToType.each do |int, type|
|
534
|
+
return false unless type == otherType.intToType[int]
|
535
|
+
end
|
536
|
+
true
|
537
|
+
end
|
538
|
+
|
539
|
+
def initialize(intToType)
|
540
|
+
intToType.keys.each do |i|
|
541
|
+
raise MinimumSizeError("Union's integer representations must be > 0, instead got: #{i}") if i < 0 or !i.is_a?(Integer)
|
542
|
+
end
|
543
|
+
raise MinimumSizeError("Union must have at least one type") if intToType.keys.size < 1
|
544
|
+
@intToType = intToType
|
545
|
+
end
|
546
|
+
|
547
|
+
def to_schema(buffer)
|
548
|
+
buffer << "("
|
549
|
+
strs = []
|
550
|
+
@intToType.size.times do
|
551
|
+
strs << ""
|
552
|
+
end
|
553
|
+
@intToType.values.each_with_index.map { |type, i| type.to_schema(strs[i]) }
|
554
|
+
buffer << strs.join(" | ")
|
555
|
+
buffer << ")"
|
556
|
+
end
|
557
|
+
|
558
|
+
def encode(msg, buffer)
|
559
|
+
type = msg[:type]
|
560
|
+
value = msg[:value]
|
561
|
+
unionTypeInt = nil
|
562
|
+
unionType = nil
|
563
|
+
@intToType.each do |int, typ|
|
564
|
+
if type.class == typ.class
|
565
|
+
unionTypeInt = int
|
566
|
+
unionType = typ
|
567
|
+
break
|
568
|
+
end
|
569
|
+
end
|
570
|
+
raise SchemaMismatch("Unable to find given type in union: #{@intToType.inspect}, type: #{type}") if unionType.nil? || unionTypeInt.nil?
|
571
|
+
Uint.new.encode(unionTypeInt, buffer)
|
572
|
+
unionType.encode(value, buffer)
|
573
|
+
end
|
574
|
+
|
575
|
+
def decode(msg)
|
576
|
+
int, rest = Uint.new.decode(msg)
|
577
|
+
type = @intToType[int]
|
578
|
+
value, rest = type.decode(rest)
|
579
|
+
return { value: value, type: type }, rest
|
364
580
|
end
|
365
581
|
end
|
366
582
|
|
367
583
|
class Struct < BaseType
|
584
|
+
attr_accessor :mapping
|
585
|
+
|
586
|
+
def cycle_search(seen)
|
587
|
+
seen.add(self)
|
588
|
+
@mapping.values.each do |val|
|
589
|
+
val.cycle_search(seen)
|
590
|
+
end
|
591
|
+
seen.pop
|
592
|
+
end
|
593
|
+
|
594
|
+
def [](key)
|
595
|
+
@mapping[key]
|
596
|
+
end
|
597
|
+
|
368
598
|
def ==(otherType)
|
369
599
|
return false unless otherType.class == BareTypes::Struct
|
370
600
|
@mapping.each do |k, v|
|
371
601
|
return false unless otherType.mapping[k] == v
|
372
602
|
end
|
373
|
-
|
374
|
-
end
|
375
|
-
|
376
|
-
def
|
377
|
-
@
|
603
|
+
true
|
604
|
+
end
|
605
|
+
|
606
|
+
def finalize_references(schema)
|
607
|
+
return if @finalized
|
608
|
+
@finalized = true
|
609
|
+
@mapping.each do |key, val|
|
610
|
+
if val.is_a?(Symbol)
|
611
|
+
@mapping[key] = Reference.new(val, schema[val])
|
612
|
+
begin
|
613
|
+
@mapping[key].ref.finalize_references(schema)
|
614
|
+
rescue NoMethodError => e
|
615
|
+
puts "err"
|
616
|
+
end
|
617
|
+
else
|
618
|
+
val.finalize_references(schema)
|
619
|
+
end
|
620
|
+
end
|
378
621
|
end
|
379
622
|
|
380
623
|
def initialize(symbolToType)
|
381
|
-
# Mapping from symbols to Bare types
|
624
|
+
# Mapping from symbols to Bare types (or possibly symbols before finalizing)
|
382
625
|
symbolToType.keys.each do |k|
|
383
|
-
raise BareException("Struct keys must be symbols") unless k.is_a?(Symbol)
|
384
|
-
|
385
|
-
|
626
|
+
raise BareException.new("Struct keys must be symbols") unless k.is_a?(Symbol)
|
627
|
+
if (!symbolToType[k].class.ancestors.include?(BaseType) && !symbolToType[k].is_a?(Symbol))
|
628
|
+
raise BareException.new("Struct values must be a BareTypes::TYPE or a symbol with the same
|
629
|
+
name as a user defined type\nInstead got: #{symbolToType[k].inspect}")
|
630
|
+
end
|
631
|
+
raise VoidUsedOutsideTaggedSet.new("Void types may only be used as members of the set of types in a tagged union. Void type used as struct key") if symbolToType.class == BareTypes::Void
|
386
632
|
end
|
387
633
|
raise("Struct must have at least one field") if symbolToType.keys.size == 0
|
388
634
|
@mapping = symbolToType
|
389
635
|
end
|
390
636
|
|
391
|
-
def encode(msg)
|
392
|
-
bytes = "".b
|
637
|
+
def encode(msg, buffer)
|
393
638
|
@mapping.keys.each do |symbol|
|
394
|
-
raise SchemaMismatch("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
|
395
|
-
|
639
|
+
raise SchemaMismatch.new("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
|
640
|
+
@mapping[symbol].encode(msg[symbol], buffer)
|
396
641
|
end
|
397
|
-
return bytes
|
398
642
|
end
|
399
643
|
|
400
644
|
def decode(msg)
|
401
645
|
hash = Hash.new
|
402
646
|
rest = msg
|
403
647
|
@mapping.keys.each do |symbol|
|
404
|
-
|
405
|
-
hash[symbol] =
|
406
|
-
rest = output[:rest]
|
648
|
+
value, rest = @mapping[symbol].decode(rest)
|
649
|
+
hash[symbol] = value
|
407
650
|
end
|
408
|
-
return
|
651
|
+
return hash, rest
|
652
|
+
end
|
653
|
+
|
654
|
+
def to_schema(buffer)
|
655
|
+
buffer << "{"
|
656
|
+
@mapping.each do |symbol, type|
|
657
|
+
buffer << " #{symbol}: "
|
658
|
+
type.to_schema(buffer)
|
659
|
+
buffer << "\n"
|
660
|
+
end
|
661
|
+
buffer << "}"
|
409
662
|
end
|
410
663
|
end
|
411
664
|
|
412
665
|
class Array < BaseType
|
413
666
|
def ==(otherType)
|
414
|
-
|
667
|
+
otherType.class == BareTypes::Array && otherType.type == self.type
|
668
|
+
end
|
669
|
+
|
670
|
+
def cycle_search(seen)
|
671
|
+
seen.add(self)
|
672
|
+
@type.cycle_search(seen)
|
673
|
+
seen.pop
|
415
674
|
end
|
416
675
|
|
417
676
|
def type
|
418
|
-
|
677
|
+
@type
|
678
|
+
end
|
679
|
+
|
680
|
+
def to_schema(buffer)
|
681
|
+
buffer << "[]"
|
682
|
+
@type.to_schema(buffer)
|
683
|
+
end
|
684
|
+
|
685
|
+
def finalize_references(schema)
|
686
|
+
return if @finalized
|
687
|
+
@finalized = true
|
688
|
+
if @type.is_a?(Symbol)
|
689
|
+
@type = Reference.new(@type, schema[@type])
|
690
|
+
else
|
691
|
+
@type.finalize_references(schema)
|
692
|
+
end
|
419
693
|
end
|
420
694
|
|
421
695
|
def initialize(type)
|
422
|
-
raise VoidUsedOutsideTaggedSet("Void types may only be used as members of the set of types in a tagged union.") if type.class == BareTypes::Void
|
696
|
+
raise VoidUsedOutsideTaggedSet.new("Void types may only be used as members of the set of types in a tagged union.") if type.class == BareTypes::Void
|
423
697
|
@type = type
|
424
698
|
end
|
425
699
|
|
426
|
-
def encode(msg)
|
427
|
-
|
700
|
+
def encode(msg, buffer)
|
701
|
+
Uint.new.encode(msg.size, buffer)
|
428
702
|
msg.each do |item|
|
429
|
-
|
703
|
+
@type.encode(item, buffer)
|
430
704
|
end
|
431
|
-
return bytes
|
432
705
|
end
|
433
706
|
|
434
707
|
def decode(msg)
|
435
|
-
output = Uint.new.decode(msg)
|
436
708
|
arr = []
|
437
|
-
arrayLen =
|
709
|
+
arrayLen, rest = Uint.new.decode(msg)
|
438
710
|
lastSize = msg.size + 1 # Make sure msg size monotonically decreasing
|
439
711
|
(arrayLen - 1).downto(0) do
|
440
|
-
|
441
|
-
arr <<
|
442
|
-
break if
|
443
|
-
lastSize =
|
712
|
+
arrVal, rest = @type.decode(rest)
|
713
|
+
arr << arrVal
|
714
|
+
break if rest.nil? || rest.size == 0 || lastSize <= rest.size
|
715
|
+
lastSize = rest.size
|
444
716
|
end
|
445
|
-
return
|
717
|
+
return arr, rest
|
446
718
|
end
|
447
719
|
end
|
448
720
|
|
449
721
|
class ArrayFixedLen < BaseType
|
722
|
+
attr_accessor :type, :size
|
723
|
+
|
724
|
+
def cycle_search(seen)
|
725
|
+
seen.add(self)
|
726
|
+
@type.cycle_search(seen)
|
727
|
+
seen.pop
|
728
|
+
end
|
729
|
+
|
450
730
|
def ==(otherType)
|
451
731
|
return otherType.class == BareTypes::ArrayFixedLen && otherType.type == @type && otherType.size == @size
|
452
732
|
end
|
453
733
|
|
734
|
+
def finalize_references(schema)
|
735
|
+
return if @finalized
|
736
|
+
@finalized = true
|
737
|
+
if @type.is_a?(Symbol)
|
738
|
+
@type = Reference.new(@type, schema[@type])
|
739
|
+
else
|
740
|
+
@type.finalize_references(schema)
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
454
744
|
def initialize(type, size)
|
455
745
|
@type = type
|
456
746
|
@size = size
|
457
|
-
raise VoidUsedOutsideTaggedSet("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
|
458
|
-
raise MinimumSizeError("
|
459
|
-
end
|
460
|
-
|
461
|
-
def type
|
462
|
-
@type
|
463
|
-
end
|
464
|
-
|
465
|
-
def size
|
466
|
-
@size
|
747
|
+
raise VoidUsedOutsideTaggedSet.new("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
|
748
|
+
raise MinimumSizeError.new("ArrayFixedLen size must be > 0") if size < 1
|
467
749
|
end
|
468
750
|
|
469
|
-
def encode(arr)
|
470
|
-
raise SchemaMismatch("This
|
471
|
-
bytes = ""
|
751
|
+
def encode(arr, buffer)
|
752
|
+
raise SchemaMismatch.new("This ArrayFixedLen is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
|
472
753
|
arr.each do |item|
|
473
|
-
|
754
|
+
@type.encode(item, buffer)
|
474
755
|
end
|
475
|
-
return bytes
|
476
756
|
end
|
477
757
|
|
478
|
-
def decode(
|
758
|
+
def decode(rest)
|
479
759
|
array = []
|
480
|
-
rest = msg
|
481
760
|
@size.times do
|
482
|
-
|
483
|
-
|
484
|
-
array << output[:value]
|
761
|
+
arrVal, rest = @type.decode(rest)
|
762
|
+
array << arrVal
|
485
763
|
end
|
486
|
-
return
|
764
|
+
return array, rest
|
765
|
+
end
|
766
|
+
|
767
|
+
def to_schema(buffer)
|
768
|
+
buffer << "[#{@size}]"
|
769
|
+
@type.to_schema(buffer)
|
487
770
|
end
|
488
771
|
end
|
489
772
|
|
@@ -496,6 +779,16 @@ class BareTypes
|
|
496
779
|
return true
|
497
780
|
end
|
498
781
|
|
782
|
+
def to_schema(buffer)
|
783
|
+
buffer << "{\n"
|
784
|
+
@valToInt.each do |name, repr|
|
785
|
+
buffer << " #{name} = #{repr}\n"
|
786
|
+
end
|
787
|
+
buffer << "}"
|
788
|
+
end
|
789
|
+
|
790
|
+
def finalize_references(schema) end
|
791
|
+
|
499
792
|
def intToVal
|
500
793
|
@intToVal
|
501
794
|
end
|
@@ -503,9 +796,9 @@ class BareTypes
|
|
503
796
|
def initialize(source)
|
504
797
|
@intToVal = {}
|
505
798
|
@valToInt = {}
|
506
|
-
raise BareException("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
|
507
|
-
raise BareException("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
|
508
|
-
raise EnumValueError("Enum must have unique values") if source.values.to_set.size != source.values.size
|
799
|
+
raise BareException.new("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
|
800
|
+
raise BareException.new("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
|
801
|
+
raise EnumValueError.new("Enum must have unique values") if source.values.to_set.size != source.values.size
|
509
802
|
source.each do |k, v|
|
510
803
|
raise("Enum keys must be positive integers") if k < 0
|
511
804
|
@intToVal[k.to_i] = v
|
@@ -513,18 +806,15 @@ class BareTypes
|
|
513
806
|
end
|
514
807
|
end
|
515
808
|
|
516
|
-
def encode(msg)
|
517
|
-
raise SchemaMismatch("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
|
809
|
+
def encode(msg, buffer)
|
810
|
+
raise SchemaMismatch.new("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
|
518
811
|
integerRep = @valToInt[msg]
|
519
|
-
|
520
|
-
return encoded
|
812
|
+
BareTypes::Uint.new.encode(integerRep, buffer)
|
521
813
|
end
|
522
814
|
|
523
815
|
def decode(msg)
|
524
|
-
|
525
|
-
|
526
|
-
rest = output[:rest]
|
527
|
-
return {value: @intToVal[value], rest: rest}
|
816
|
+
value, rest = BareTypes::Uint.new.decode(msg)
|
817
|
+
return @intToVal[value], rest
|
528
818
|
end
|
529
819
|
end
|
530
820
|
end
|
@@ -540,4 +830,4 @@ def _get_next_7_bits_as_byte(integer, base = 128)
|
|
540
830
|
end
|
541
831
|
yield(byte)
|
542
832
|
end
|
543
|
-
end
|
833
|
+
end
|