bare-rb 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdfcd51a2a757a2cb2c532d1281afe227150518a6feb625466a5f25fac16b84b
4
- data.tar.gz: ca3ed0f25556c996c62ff70a31ef3c50d9a3e6cad0d712eb8e428013a5af0af3
3
+ metadata.gz: 5b1147744e8da154541d6591f1e78929ad90a57ba806541a03cc5e770b43af6b
4
+ data.tar.gz: 121a6ba57b86dc43f9e1b65145cc35e5c2174934e97bfdc142ddcd848f74deae
5
5
  SHA512:
6
- metadata.gz: 222f83030bee145a42b3ae2ef890316f4969502f3a8e9704e3b84ffadaab0866d71163bf97b0d3f90ec02a065336343b20149375b9e628c646d8b342d0e5b27d
7
- data.tar.gz: e757dbf048dd0f65392561a9034b3407d2fe9e2e942bcf181b3c7a25847a03e9eb515b66ef74b23115b37a94751daeae04eb4190b218a0c2dcbe2ab988ca3256
6
+ metadata.gz: 8490934a87328cf339307924d7268e71e0c4c58336021294c2e957d618ab871ecc1a7d05f07ae72025e214f0fab7b64df7d31d37c3b6cbea8687315a523cb7f0
7
+ data.tar.gz: d2930be08e535b50638eeda6814cd7d2e1544eead403a4f4efd81817cc54eb352a0e52575460f612ba9a5127949d61c6724c7a724e0feac3f7a2c9d54906da36
@@ -4,20 +4,62 @@ require_relative "lexer"
4
4
  require_relative "parser"
5
5
 
6
6
  class Bare
7
+ def self.encode(msg, schema, type=nil)
8
+ if schema.is_a?(Bare::Schema)
9
+ raise NoTypeProvided("To encode with a schema as opposed to a raw type you must specify which type in the same you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
10
+ return schema[type].encode(msg)
11
+ else
12
+ schema.encode(msg)
13
+ end
14
+ end
15
+
16
+ def self.decode(msg, schema, type=nil)
17
+ if schema.is_a?(Bare::Schema)
18
+ raise NoTypeProvided("To decode with a schema as opposed to a raw type you must specify which type in the same you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
19
+ return schema[type].decode(msg)[:value]
20
+ else
21
+ schema.decode(msg)[:value]
22
+ end
23
+ end
7
24
 
8
25
  def self.parse_schema(path)
9
26
  # Hash of class names to BARE ASTs
10
27
  # Eg. types['Customer'] == Bare.i32
11
28
  types = parser(lexer(path))
12
- return types
29
+ Bare.Schema(types)
13
30
  end
14
31
 
15
- def self.encode(msg, schema)
16
- return schema.encode(msg)
32
+ def self.Schema(hash)
33
+ Bare::Schema.new(hash)
17
34
  end
18
35
 
19
- def self.decode(msg, schema)
20
- return schema.decode(msg)[:value]
36
+ class Schema
37
+
38
+ def ==(otherSchema)
39
+ return false unless otherSchema.is_a?(Bare::Schema)
40
+ return @types == otherSchema.types
41
+ end
42
+
43
+ def types
44
+ @types
45
+ end
46
+
47
+ def [](key)
48
+ return @types[key]
49
+ end
50
+
51
+ def initialize(types)
52
+ @types = types
53
+ @types.keys.each do |key|
54
+ if @types[key].is_a?(Symbol)
55
+ @types[key] = @types[@types[key]]
56
+ else
57
+ # Users may user symbols to reference not yet defined types
58
+ # here we recursively call our bare classes to finalize their types
59
+ @types[key].finalize_references(@types)
60
+ end
61
+ end
62
+ end
21
63
  end
22
64
 
23
65
  # These classes are wrapped in methods for ergonomics.
@@ -118,5 +160,7 @@ class Bare
118
160
  def self.Enum(*opts)
119
161
  return BareTypes::Enum.new(*opts)
120
162
  end
163
+
164
+
121
165
  end
122
166
 
@@ -5,6 +5,12 @@ class BareException < StandardError
5
5
  end
6
6
  end
7
7
 
8
+ class NoTypeProvided < BareException
9
+ def initialize(msg = nil)
10
+ super
11
+ end
12
+ end
13
+
8
14
  class SchemaParsingException < BareException
9
15
  def initialize(msg=nil)
10
16
  super
@@ -44,7 +44,7 @@ def lexer(path)
44
44
  tokens << :bar
45
45
  elsif match = /^([0-9]+)/.match(line)
46
46
  tokens << match[0].to_i
47
- line = line[(match.size + 1)..]
47
+ line = line[(match[0].size)..]
48
48
  next
49
49
  elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]+/.match(line)
50
50
  tokens << match[0]
@@ -49,6 +49,31 @@ class Parser
49
49
  return tokens[1..], enum
50
50
  end
51
51
 
52
+ def parse_union(tokens)
53
+ count = 0
54
+ union_hash = {}
55
+ # type A_UNION ( int | uint | data = 7 | f32 )
56
+ while tokens[0] != :close_paren
57
+ if tokens[0] == :bar
58
+ tokens = tokens[1..]
59
+ else
60
+ if tokens[1] == :equal
61
+ raise SchemaParsingException.new("Equals sign in union must be followed by a number") unless tokens[2].is_a?(Numeric)
62
+ count = tokens[2]
63
+ tokens, type = self.parse(tokens)
64
+ tokens = tokens[2..]
65
+ union_hash[count] = type
66
+ count += 1
67
+ else
68
+ tokens, type = self.parse(tokens)
69
+ union_hash[count] = type
70
+ count += 1
71
+ end
72
+ end
73
+ end
74
+ return tokens, union_hash
75
+ end
76
+
52
77
  def parse_struct(tokens)
53
78
  struct_fields = {}
54
79
  while tokens.size >= 2 and tokens[1] == :colon
@@ -66,20 +91,39 @@ class Parser
66
91
  tokens, type = self.parse(tokens[2..])
67
92
  @definitions[name.to_sym] = type
68
93
  elsif tokens[0] == "map"
69
- raise SchemaParsingException("Map must be followed by a '[' eg. map[string]data") if tokens[1] != :open_brace
94
+ raise SchemaParsingException.new("Map must be followed by a '[' eg. map[string]data") if tokens[1] != :open_brace
70
95
  tokens, map_from_type = parse(tokens[2..])
71
- raise SchemaParsingException("Map to type must be followed by a ']' eg. map[string]data") if tokens[0] != :close_brace
96
+ raise SchemaParsingException.new("Map to type must be followed by a ']' eg. map[string]data") if tokens[0] != :close_brace
72
97
  tokens, map_to_type = parse(tokens[1..])
73
- return tokens, Bare.Map(map_from_type,map_to_type)
98
+ return tokens, Bare.Map(map_from_type, map_to_type)
99
+ elsif tokens[0] == "data" && tokens.size > 3 && tokens[1] == :less_than
100
+ raise SchemaParsingException.new("data< must be followed by a number for a fixed sized bare data") unless tokens[2].is_a?(Numeric)
101
+ raise SchemaParsingException.new("data<# must be followed by a >") unless tokens[3] == :greater_than
102
+ return tokens[4..], Bare.DataFixedLen(tokens[2])
74
103
  elsif tokens[0] == "enum"
75
104
  name = tokens[1]
76
- raise SchemaParsingException("Enum must be followed by a '{'") if tokens[2] != :open_block
105
+ raise SchemaParsingException.new("Enum must be followed by a '{'") if tokens[2] != :open_block
77
106
  tokens, enum = parse_enum(tokens[3..])
78
107
  @definitions[name.to_sym] = enum
79
- return tokens, enum
108
+ elsif tokens[0] == "optional"
109
+ raise SchemaParsingException.new("Optional must be followed by a '< TYPE > you are missing the first <'") if tokens[1] != :less_than
110
+ tokens, optional_type = self.parse(tokens[2..])
111
+ raise SchemaParsingException.new("Optional must be followed by a '< TYPE >' you are missing the last >") if tokens[0] != :greater_than
112
+ return tokens[1..], Bare.Optional(optional_type)
80
113
  elsif tokens[0] == :open_brace
81
- tokens, arr_type = parse(tokens[2..])
82
- return tokens, Bare.Array(arr_type)
114
+ if tokens[1].is_a?(Numeric)
115
+ size = tokens[1]
116
+ raise SchemaParsingException.new("Fixed Length Array size must be followed by a ']'") if tokens[2] != :close_brace
117
+ tokens, arr_type = parse(tokens[3..])
118
+ return tokens, Bare.ArrayFixedLen(arr_type, size)
119
+ else
120
+ tokens, arr_type = parse(tokens[2..])
121
+ return tokens, Bare.Array(arr_type)
122
+ end
123
+ elsif tokens[0] == :open_paren
124
+ tokens, union_hash = parse_union(tokens[1..])
125
+ raise SchemaParsingException.new("Union must be followed by a ')'") if tokens[0] != :close_paren
126
+ return tokens[1..], Bare.Union(union_hash)
83
127
  elsif tokens[0] == :open_block
84
128
  tokens, struct_fields = parse_struct(tokens[1..])
85
129
  strct = Bare.Struct(struct_fields)
@@ -87,6 +131,10 @@ class Parser
87
131
  elsif @primitives.include?(tokens[0])
88
132
  type = @primitives[tokens[0]]
89
133
  return tokens[1..], type
134
+ elsif @definitions.keys.include?(tokens[0].to_sym) # User defined type
135
+ return tokens[1..], @definitions[tokens[0].to_sym]
136
+ elsif tokens[0].is_a?(String) && tokens[0][0].upcase == tokens[0][0] # Not yet defined user type
137
+ return tokens[1..], tokens[0].to_sym
90
138
  else
91
139
  raise SchemaParsingException.new("Unable to parse token: #{tokens[0]}")
92
140
  end
@@ -3,6 +3,10 @@ require_relative './exceptions'
3
3
  class BareTypes
4
4
 
5
5
  class BaseType
6
+ def initialize
7
+ @finalized = false
8
+ super
9
+ end
6
10
  end
7
11
 
8
12
  class BarePrimitive < BaseType
@@ -10,9 +14,14 @@ class BareTypes
10
14
  # Eg. Uint.new == Uint.new
11
15
  # But Union.new(types1) != Union.new(types2)
12
16
  # since unions could have different sets of types
17
+
13
18
  def ==(other)
14
19
  self.class == other.class
15
20
  end
21
+
22
+ def finalize_references(schema)
23
+ end
24
+
16
25
  end
17
26
 
18
27
  class Int < BarePrimitive
@@ -22,11 +31,12 @@ class BareTypes
22
31
  mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
23
32
  return Uint.new.encode(mappedInteger)
24
33
  end
34
+
25
35
  def decode(msg)
26
36
  output = Uint.new.decode(msg)
27
37
  unmapped = output[:value]
28
- unmapped = unmapped.odd? ? (unmapped + 1) / - 2 : unmapped / 2
29
- return { value: unmapped, rest: output[:rest] }
38
+ unmapped = unmapped.odd? ? (unmapped + 1) / -2 : unmapped / 2
39
+ return {value: unmapped, rest: output[:rest]}
30
40
  end
31
41
  end
32
42
 
@@ -34,6 +44,7 @@ class BareTypes
34
44
  def encode(msg)
35
45
  return "".b
36
46
  end
47
+
37
48
  def decode(msg)
38
49
  return {value: nil, rest: msg}
39
50
  end
@@ -43,6 +54,7 @@ class BareTypes
43
54
  def encode(msg)
44
55
  return [msg].pack("e")
45
56
  end
57
+
46
58
  def decode(msg)
47
59
  return {value: msg.unpack("e")[0], rest: msg[4..msg.size]}
48
60
  end
@@ -52,6 +64,7 @@ class BareTypes
52
64
  def encode(msg)
53
65
  return [msg].pack("E")
54
66
  end
67
+
55
68
  def decode(msg)
56
69
  return {value: msg.unpack("E")[0], rest: msg[8..msg.size]}
57
70
  end
@@ -69,11 +82,12 @@ class BareTypes
69
82
  bytes << encodedString
70
83
  return bytes
71
84
  end
85
+
72
86
  def decode(msg)
73
87
  output = Uint.new.decode(msg)
74
88
  strLen = output[:value]
75
- string = output[:rest][0..strLen-1]
76
- return {value: string.force_encoding("utf-8"), rest: output[:rest][strLen..output[:rest].size] }
89
+ string = output[:rest][0..strLen - 1]
90
+ return {value: string.force_encoding("utf-8"), rest: output[:rest][strLen..output[:rest].size]}
77
91
  end
78
92
  end
79
93
 
@@ -82,6 +96,16 @@ class BareTypes
82
96
  return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
83
97
  end
84
98
 
99
+ def finalize_references(schema)
100
+ return if @finalized
101
+ @finalized = true
102
+ if @optionalType.is_a?(Symbol)
103
+ @optionalType = schema[@optionalType]
104
+ else
105
+ @optionalType.finalize_references(schema)
106
+ end
107
+ end
108
+
85
109
  def optionalType
86
110
  @optionalType
87
111
  end
@@ -115,9 +139,23 @@ class BareTypes
115
139
  return otherType.class == BareTypes::Map && otherType.from == @from && otherType.to == @to
116
140
  end
117
141
 
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
150
+ end
151
+
118
152
  def initialize(fromType, toType)
119
153
  raise VoidUsedOutsideTaggedSet if fromType.class == BareTypes::Void or toType.class == BareTypes::Void
120
- raise MapKeyError("Map keys must use a primitive type which is not data or data<length>.") if !fromType.class.ancestors.include?(BarePrimitive) || fromType.is_a?(BareTypes::Data) || fromType.is_a?(BareTypes::DataFixedLen)
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
121
159
  @from = fromType
122
160
  @to = toType
123
161
  end
@@ -154,10 +192,23 @@ class BareTypes
154
192
  end
155
193
 
156
194
  class Union < BarePrimitive
195
+
157
196
  def intToType
158
197
  @intToType
159
198
  end
160
199
 
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
210
+ end
211
+
161
212
  def ==(otherType)
162
213
  return false unless otherType.is_a?(BareTypes::Union)
163
214
  @intToType.each do |int, type|
@@ -210,6 +261,9 @@ class BareTypes
210
261
  return @length
211
262
  end
212
263
 
264
+ def finalize_references(schema)
265
+ end
266
+
213
267
  def initialize(length)
214
268
  raise MinimumSizeError("DataFixedLen must have a length greater than 0, got: #{length.inspect}") if length < 1
215
269
  @length = length
@@ -225,6 +279,10 @@ class BareTypes
225
279
  end
226
280
 
227
281
  class Data < BarePrimitive
282
+
283
+ def finalize_references(schema)
284
+ end
285
+
228
286
  def encode(msg)
229
287
  bytes = Uint.new.encode(msg.size)
230
288
  bytes << msg
@@ -235,11 +293,15 @@ class BareTypes
235
293
  output = Uint.new.decode(msg)
236
294
  rest = output[:rest]
237
295
  dataSize = output[:value]
238
- return {value: rest[0..dataSize-1], rest: rest[dataSize..]}
296
+ return {value: rest[0..dataSize - 1], rest: rest[dataSize..]}
239
297
  end
240
298
  end
241
299
 
242
300
  class Uint < BarePrimitive
301
+
302
+ def finalize_references(schema)
303
+ end
304
+
243
305
  def encode(msg)
244
306
  bytes = "".b
245
307
  _get_next_7_bits_as_byte(msg, 128) do |byte|
@@ -365,6 +427,11 @@ class BareTypes
365
427
  end
366
428
 
367
429
  class Struct < BaseType
430
+
431
+ def [](key)
432
+ return @mapping[key]
433
+ end
434
+
368
435
  def ==(otherType)
369
436
  return false unless otherType.class == BareTypes::Struct
370
437
  @mapping.each do |k, v|
@@ -373,16 +440,31 @@ class BareTypes
373
440
  return true
374
441
  end
375
442
 
443
+ def finalize_references(schema)
444
+ return if @finalized
445
+ @finalized = true
446
+ @mapping.each do |key, val|
447
+ if val.is_a?(Symbol)
448
+ @mapping[key] = schema[val]
449
+ else
450
+ val.finalize_references(schema)
451
+ end
452
+ end
453
+ end
454
+
376
455
  def mapping
377
456
  @mapping
378
457
  end
379
458
 
380
459
  def initialize(symbolToType)
381
- # Mapping from symbols to Bare types
460
+ # Mapping from symbols to Bare types (or possibly symbols before finalizing)
382
461
  symbolToType.keys.each do |k|
383
- raise BareException("Struct keys must be symbols") unless k.is_a?(Symbol)
384
- raise BareException("Struct values must be a BareTypes::TYPE\nInstead got: #{symbolToType[k].inspect}") unless symbolToType[k].class.ancestors.include?(BaseType)
385
- raise VoidUsedOutsideTaggedSet("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
462
+ raise BareException.new("Struct keys must be symbols") unless k.is_a?(Symbol)
463
+ if (!symbolToType[k].class.ancestors.include?(BaseType) && !symbolToType[k].is_a?(Symbol))
464
+ raise BareException.new("Struct values must be a BareTypes::TYPE or a symbol with the same
465
+ name as a user defined type\nInstead got: #{symbolToType[k].inspect}")
466
+ end
467
+ 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
468
  end
387
469
  raise("Struct must have at least one field") if symbolToType.keys.size == 0
388
470
  @mapping = symbolToType
@@ -391,7 +473,7 @@ class BareTypes
391
473
  def encode(msg)
392
474
  bytes = "".b
393
475
  @mapping.keys.each do |symbol|
394
- raise SchemaMismatch("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
476
+ raise SchemaMismatch.new("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
395
477
  bytes << @mapping[symbol].encode(msg[symbol])
396
478
  end
397
479
  return bytes
@@ -418,8 +500,18 @@ class BareTypes
418
500
  return @type
419
501
  end
420
502
 
503
+ def finalize_references(schema)
504
+ return if @finalized
505
+ @finalized = true
506
+ if @type.is_a?(Symbol)
507
+ @type = schema[@type]
508
+ else
509
+ @type.finalize_references(schema)
510
+ end
511
+ end
512
+
421
513
  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
514
+ 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
515
  @type = type
424
516
  end
425
517
 
@@ -451,11 +543,21 @@ class BareTypes
451
543
  return otherType.class == BareTypes::ArrayFixedLen && otherType.type == @type && otherType.size == @size
452
544
  end
453
545
 
546
+ def finalize_references(schema)
547
+ return if @finalized
548
+ @finalized = true
549
+ if @type.is_a?(Symbol)
550
+ @type = schema[@type]
551
+ else
552
+ @type.finalize_references(schema)
553
+ end
554
+ end
555
+
454
556
  def initialize(type, size)
455
557
  @type = type
456
558
  @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("FixedLenArray size must be > 0") if size < 1
559
+ 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
459
561
  end
460
562
 
461
563
  def type
@@ -467,7 +569,7 @@ class BareTypes
467
569
  end
468
570
 
469
571
  def encode(arr)
470
- raise SchemaMismatch("This FixLenArray is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
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
471
573
  bytes = ""
472
574
  arr.each do |item|
473
575
  bytes << @type.encode(item)
@@ -496,6 +598,10 @@ class BareTypes
496
598
  return true
497
599
  end
498
600
 
601
+
602
+ def finalize_references(schema)
603
+ end
604
+
499
605
  def intToVal
500
606
  @intToVal
501
607
  end
@@ -503,9 +609,9 @@ class BareTypes
503
609
  def initialize(source)
504
610
  @intToVal = {}
505
611
  @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
612
+ raise BareException.new("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
613
+ raise BareException.new("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
614
+ raise EnumValueError.new("Enum must have unique values") if source.values.to_set.size != source.values.size
509
615
  source.each do |k, v|
510
616
  raise("Enum keys must be positive integers") if k < 0
511
617
  @intToVal[k.to_i] = v
@@ -514,7 +620,7 @@ class BareTypes
514
620
  end
515
621
 
516
622
  def encode(msg)
517
- raise SchemaMismatch("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
623
+ raise SchemaMismatch.new("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
518
624
  integerRep = @valToInt[msg]
519
625
  encoded = BareTypes::Uint.new.encode(integerRep)
520
626
  return encoded
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bare-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Tracy-Amoroso