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.
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 BarePrimitive < BaseType
13
- # Types which are always equivalent to another instantiation of themselves
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 ==(other)
19
- self.class == other.class
20
- end
21
-
22
- def finalize_references(schema)
23
- end
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
- end
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
- class Int < BarePrimitive
28
- # https://developers.google.com/protocol-buffers/docs/encoding
29
- # Easy to just convert to signed and re-use uint code
30
- def encode(msg)
31
- mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
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
- def decode(msg)
36
- output = Uint.new.decode(msg)
37
- unmapped = output[:value]
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
- class Void < BarePrimitive
44
- def encode(msg)
45
- return "".b
58
+ @types.each do |key, val|
59
+ val.cycle_search(SeenList.new)
60
+ end
46
61
  end
47
62
 
48
- def decode(msg)
49
- return {value: nil, rest: msg}
63
+ def ==(otherSchema)
64
+ return false unless otherSchema.is_a?(BareTypes::Schema)
65
+ @types == otherSchema.types
50
66
  end
51
- end
52
67
 
53
- class F32 < BarePrimitive
54
- def encode(msg)
55
- return [msg].pack("e")
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 decode(msg)
59
- return {value: msg.unpack("e")[0], rest: msg[4..msg.size]}
84
+ def [](key)
85
+ return @types[key]
60
86
  end
61
87
  end
62
88
 
63
- class F64 < BarePrimitive
64
- def encode(msg)
65
- return [msg].pack("E")
66
- end
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 decode(msg)
69
- return {value: msg.unpack("E")[0], rest: msg[8..msg.size]}
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
- class String < BarePrimitive
74
- def encode(msg)
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
- class Optional < BaseType
95
- def ==(otherType)
96
- return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
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
- if @optionalType.is_a?(Symbol)
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 optionalType
110
- @optionalType
121
+ def encode(msg, buffer)
122
+ @ref.encode(msg, buffer)
111
123
  end
112
124
 
113
- def initialize(optionalType)
114
- raise VoidUsedOutsideTaggedSet() if optionalType.class == BareTypes::Void
115
- @optionalType = optionalType
125
+ def decode(msg)
126
+ @ref.decode(msg)
116
127
  end
117
128
 
118
- def encode(msg)
119
- if msg.nil?
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 Map < BaseType
138
- def ==(otherType)
139
- return otherType.class == BareTypes::Map && otherType.from == @from && otherType.to == @to
140
- end
134
+ class BarePrimitive < BaseType
141
135
 
142
- def finalize_references(schema)
143
- return if @finalized
144
- @finalized = true
145
- if @from.is_a?(Symbol)
146
- @to = schema[@to]
147
- else
148
- @to.finalize_references(schema)
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 initialize(fromType, toType)
153
- raise VoidUsedOutsideTaggedSet if fromType.class == BareTypes::Void or toType.class == BareTypes::Void
154
- if !fromType.class.ancestors.include?(BarePrimitive) ||
155
- fromType.is_a?(BareTypes::Data) ||
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
- def from
164
- @from
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 to
168
- @to
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
- def encode(msg)
172
- bytes = Uint.new.encode(msg.size)
173
- msg.each do |from, to|
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
- hash = Hash.new
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 Union < BarePrimitive
195
-
196
- def intToType
197
- @intToType
179
+ class F32 < BarePrimitive
180
+ def encode(msg, buffer)
181
+ buffer << [msg].pack("e")
198
182
  end
199
183
 
200
- def finalize_references(schema)
201
- return if @finalized
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
- def ==(otherType)
213
- return false unless otherType.is_a?(BareTypes::Union)
214
- @intToType.each do |int, type|
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 initialize(intToType)
221
- intToType.keys.each do |i|
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
- def encode(msg)
229
- type = msg[:type]
230
- value = msg[:value]
231
- unionTypeInt = nil
232
- unionType = nil
233
- @intToType.each do |int, typ|
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
- raise SchemaMismatch("Unable to find given type in union: #{@intToType.inspect}, type: #{type}") if unionType.nil? || unionTypeInt.nil?
241
- bytes = Uint.new.encode(unionTypeInt)
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
- unionTypeInt = Uint.new.decode(msg)
248
- int = unionTypeInt[:value]
249
- type = @intToType[int]
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 length
261
- return @length
222
+ def to_schema(buffer)
223
+ buffer << "data<#{@length}>"
262
224
  end
263
225
 
264
- def finalize_references(schema)
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
- return msg
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 {value: msg[0..@length], rest: msg[@length..msg.size]}
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
- bytes = Uint.new.encode(msg.size)
288
- bytes << msg
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
- output = Uint.new.decode(msg)
294
- rest = output[: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
- return bytes
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("CCCCCCCCC")
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 {value: sum, rest: msg[(i + 1)..msg.size]}
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
- return [msg].pack("C")
303
+ def encode(msg, buffer)
304
+ buffer << [msg].pack("C")
342
305
  end
343
306
 
344
307
  def decode(msg)
345
- return {value: msg[0].unpack("C")[0], rest: msg[1..msg.size]}
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
- return [msg].pack("v")
313
+ def encode(msg, buffer)
314
+ buffer << [msg].pack("v")
352
315
  end
353
316
 
354
317
  def decode(msg)
355
- return {value: msg.unpack("v")[0], rest: msg[2..msg.size]}
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
- return [msg].pack("V")
323
+ def encode(msg, buffer)
324
+ buffer << [msg].pack("V")
362
325
  end
363
326
 
364
327
  def decode(msg)
365
- return {value: msg.unpack("V")[0], rest: msg[4..msg.size]}
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
- return [msg].pack("Q")
333
+ def encode(msg, buffer)
334
+ buffer << [msg].pack("Q")
372
335
  end
373
336
 
374
337
  def decode(msg)
375
- return {value: msg.unpack("Q")[0], rest: [8..msg.size]}
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
- return [msg].pack("c")
343
+ def encode(msg, buffer)
344
+ buffer << [msg].pack("c")
382
345
  end
383
346
 
384
347
  def decode(msg)
385
- return {value: msg[0].unpack("c")[0], rest: msg[1..msg.size]}
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
- return [msg].pack("s<")
353
+ def encode(msg, buffer)
354
+ buffer << [msg].pack("s<")
392
355
  end
393
356
 
394
357
  def decode(msg)
395
- return {value: msg.unpack('s<')[0], rest: msg[2..msg.size]}
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
- return [msg].pack("l<")
363
+ def encode(msg, buffer)
364
+ buffer << [msg].pack("l<")
402
365
  end
403
366
 
404
367
  def decode(msg)
405
- return {value: msg.unpack('l<')[0], rest: msg[4..msg.size]}
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
- return [msg].pack("q<")
373
+ def encode(msg, buffer)
374
+ buffer << [msg].pack("q<")
412
375
  end
413
376
 
414
377
  def decode(msg)
415
- return {value: msg.unpack('q<')[0], rest: msg[8..msg.size]}
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
- return msg ? "\xFF\xFF".b : "\x00\x00".b
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
- return {value: msg == "\x00\x00" ? false : true, rest: msg[1..msg.size]}
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
- return @mapping[key]
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
- return true
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
- bytes << @mapping[symbol].encode(msg[symbol])
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
- output = @mapping[symbol].decode(rest)
487
- hash[symbol] = output[:value]
488
- rest = output[:rest]
648
+ value, rest = @mapping[symbol].decode(rest)
649
+ hash[symbol] = value
489
650
  end
490
- return {value: hash, rest: rest}
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
- return otherType.class == BareTypes::Array && otherType.type == self.type
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
- return @type
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
- bytes = Uint.new.encode(msg.size)
700
+ def encode(msg, buffer)
701
+ Uint.new.encode(msg.size, buffer)
520
702
  msg.each do |item|
521
- bytes << @type.encode(item)
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 = output[:value]
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
- output = @type.decode(output[:rest])
533
- arr << output[:value]
534
- break if output[:rest].nil? || output[:rest].size == 0 || lastSize <= output[:rest].size
535
- lastSize = output[:rest].size
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 {value: arr, rest: output[:rest]}
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("FixedLenArray size must be > 0") if size < 1
748
+ raise MinimumSizeError.new("ArrayFixedLen size must be > 0") if size < 1
561
749
  end
562
750
 
563
- def type
564
- @type
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
- bytes << @type.encode(item)
754
+ @type.encode(item, buffer)
576
755
  end
577
- return bytes
578
756
  end
579
757
 
580
- def decode(msg)
758
+ def decode(rest)
581
759
  array = []
582
- rest = msg
583
760
  @size.times do
584
- output = @type.decode(rest)
585
- rest = output[:rest]
586
- array << output[:value]
761
+ arrVal, rest = @type.decode(rest)
762
+ array << arrVal
587
763
  end
588
- return {value: array, rest: rest}
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
- def finalize_references(schema)
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
- encoded = BareTypes::Uint.new.encode(integerRep)
626
- return encoded
812
+ BareTypes::Uint.new.encode(integerRep, buffer)
627
813
  end
628
814
 
629
815
  def decode(msg)
630
- output = BareTypes::Uint.new.decode(msg)
631
- value = output[:value]
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