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