bare-rb 0.0.0 → 0.1.5

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: adea5476cd77af659cb3329602479f8b80b59d0b7459dc7cf343165b7096d871
4
- data.tar.gz: 2e3f86206cc9519cd654dfcf28972a5c5c5b4fc5966143699d74f22209373088
3
+ metadata.gz: 1e8e36acbdcc47dc92e23a029edf5fac7001fbec9bd4948549cc0e682ea238b0
4
+ data.tar.gz: 86ffe342e8f2ec768b6fb222fe3575dd35eda7500ee88cff7111056a8bd422d5
5
5
  SHA512:
6
- metadata.gz: e19625e2170ed457390a6f6d06d68a67443c91f057b5310363e49d6a8c5102bb41ae068fba67f3eaecbe11f2f984bc54eae81f02c39a5222f07887920e39f8af
7
- data.tar.gz: 0e502b379a427ac5c493f0f02a8b17ab6821560adf248fccbcfac2dc31e406f08c1f29816970a50b5d82589ffdbb6f4fca2940b4e2eacda39633a95b50d58b69
6
+ metadata.gz: 555833846daa3aa6337fb836b3a7959d656dd329c3925bceb01ab27d6f873bde95e83bf965daea90f3429c73b8659b40929f6f9e1b138a631c85966910750ee2
7
+ data.tar.gz: 0f9b6ef29fd8731c688f8507d6b141e2bb0992b0074b7118cb8b13a9263b57aad9e30becbb990c94d6cc33792abad805a3cd4a44d8deab93ee3847a8de57e68a
data/lib/bare-rb.rb CHANGED
@@ -1,13 +1,67 @@
1
1
  require 'set'
2
2
  require_relative "types"
3
+ require_relative "lexer"
4
+ require_relative "parser"
3
5
 
4
6
  class Bare
5
- def self.encode(msg, schema)
6
- return schema.encode(msg)
7
- end
8
-
9
- def self.decode(msg, schema)
10
- return schema.decode(msg)[:value]
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 schema you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
10
+ 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
+ value, rest = schema[type].decode(msg)
20
+ value
21
+ else
22
+ value, rest = schema.decode(msg)
23
+ return value
24
+ end
25
+ end
26
+
27
+ def self.parse_schema(path)
28
+ # Hash of class names to BARE ASTs
29
+ # Eg. types['Customer'] == Bare.i32
30
+ types = parser(lexer(path))
31
+ Bare.Schema(types)
32
+ end
33
+
34
+ def self.Schema(hash)
35
+ Bare::Schema.new(hash)
36
+ end
37
+
38
+ class Schema
39
+ def ==(otherSchema)
40
+ return false unless otherSchema.is_a?(Bare::Schema)
41
+ @types == otherSchema.types
42
+ end
43
+
44
+ def types
45
+ @types
46
+ end
47
+
48
+ def [](key)
49
+ return @types[key]
50
+ end
51
+
52
+ def initialize(types)
53
+ @types = types
54
+ @types.keys.each do |key|
55
+ if @types[key].is_a?(Symbol)
56
+ @types[key] = @types[@types[key]]
57
+ else
58
+ # Users may use symbols to reference not yet defined types
59
+ # here we recursively call our bare classes to finalize their types
60
+ # replacing Symbols like :SomeType with a reference to the other type
61
+ @types[key].finalize_references(@types)
62
+ end
63
+ end
64
+ end
11
65
  end
12
66
 
13
67
  # These classes are wrapped in methods for ergonomics.
@@ -108,5 +162,7 @@ class Bare
108
162
  def self.Enum(*opts)
109
163
  return BareTypes::Enum.new(*opts)
110
164
  end
165
+
166
+
111
167
  end
112
168
 
data/lib/exceptions.rb CHANGED
@@ -1,9 +1,28 @@
1
+
1
2
  class BareException < StandardError
2
3
  def initialize(msg=nil)
3
4
  super
4
5
  end
5
6
  end
6
7
 
8
+ class FixedDataSizeWrong < BareException
9
+ def initialize(msg=nil)
10
+ super
11
+ end
12
+ end
13
+
14
+ class NoTypeProvided < BareException
15
+ def initialize(msg = nil)
16
+ super
17
+ end
18
+ end
19
+
20
+ class SchemaParsingException < BareException
21
+ def initialize(msg=nil)
22
+ super
23
+ end
24
+ end
25
+
7
26
  class VoidUsedOutsideTaggedSet < BareException
8
27
  def initialize(msg = "Any type which is ultimately a void type (either directly or through user-defined types) may not be used as an optional type, struct member, array member, or map key or value. Void types may only be used as members of the set of types in a tagged union.")
9
28
  super
data/lib/lexer.rb ADDED
@@ -0,0 +1,62 @@
1
+ require_relative './exceptions'
2
+
3
+ def lexer(path)
4
+ tokens = []
5
+ line_num = 0
6
+ File.open(path).each do |line|
7
+ while line.size > 0
8
+ if /^#/.match(line)
9
+ break
10
+ elsif /^\n/.match(line)
11
+ break
12
+ elsif /^ /.match(line)
13
+ line = line[1..line.size]
14
+ elsif /^</.match(line)
15
+ line = line[1..line.size]
16
+ tokens << :less_than
17
+ elsif /^>/.match(line)
18
+ line = line[1..line.size]
19
+ tokens << :greater_than
20
+ next
21
+ elsif /^{/.match(line)
22
+ line = line[1..line.size]
23
+ tokens << :open_block
24
+ elsif /^=/.match(line)
25
+ line = line[1..line.size]
26
+ tokens << :equal
27
+ elsif /^}/.match(line)
28
+ line = line[1..line.size]
29
+ tokens << :close_block
30
+ elsif /^\[/.match(line)
31
+ line = line[1..line.size]
32
+ tokens << :open_brace
33
+ elsif /^\]/.match(line)
34
+ line = line[1..line.size]
35
+ tokens << :close_brace
36
+ elsif /^\(/.match(line)
37
+ line = line[1..line.size]
38
+ tokens << :open_paren
39
+ elsif /^\)/.match(line)
40
+ line = line[1..line.size]
41
+ tokens << :close_paren
42
+ elsif /^\|/.match(line)
43
+ line = line[1..line.size]
44
+ tokens << :bar
45
+ elsif match = /^([0-9]+)/.match(line)
46
+ tokens << match[0].to_i
47
+ line = line[(match[0].size)..line.size]
48
+ next
49
+ elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]+/.match(line)
50
+ tokens << match[0]
51
+ line = line[(match[0].size)..line.size]
52
+ elsif /:/.match(line)
53
+ tokens << :colon
54
+ line = line[1..line.size]
55
+ else
56
+ raise SchemaParsingException.new("Unable to lex line #{line_num} near #{line.inspect}")
57
+ end
58
+ end
59
+ line_num += 1
60
+ end
61
+ return tokens
62
+ end
data/lib/parser.rb ADDED
@@ -0,0 +1,150 @@
1
+ require_relative './exceptions'
2
+
3
+
4
+ # enum, struct, array, fixedlenarray, data<length>
5
+ class Parser
6
+
7
+ def initialize
8
+ @definitions = {}
9
+ @primitives = {
10
+ "uint" => Bare.Uint,
11
+ "int" => Bare.Int,
12
+ "u8" => Bare.U8,
13
+ "u16" => Bare.U16,
14
+ "u32" => Bare.U32,
15
+ "u64" => Bare.U64,
16
+ "i8" => Bare.I8,
17
+ "i16" => Bare.I16,
18
+ "i32" => Bare.I32,
19
+ "i64" => Bare.I64,
20
+ "f32" => Bare.F32,
21
+ "f64" => Bare.F64,
22
+ "bool" => Bare.Bool,
23
+ "string" => Bare.String,
24
+ "data" => Bare.Data,
25
+ "void" => Bare.Void,
26
+ }
27
+ end
28
+
29
+ def definitions
30
+ @definitions
31
+ end
32
+
33
+ def parse_enum(tokens)
34
+ enum_hash = {} # {1 => "abc", 5 => :cow, 16382 => 123}
35
+ count = 0
36
+ while tokens[0] != :close_block
37
+ if tokens[1] == :equal
38
+ name = tokens[0]
39
+ int_repr = tokens[2]
40
+ enum_hash[int_repr] = name
41
+ tokens = tokens[3..tokens.size]
42
+ else
43
+ enum_hash[count] = tokens[0]
44
+ count += 1
45
+ tokens = tokens[1..tokens.size]
46
+ end
47
+ end
48
+ enum = Bare.Enum(enum_hash)
49
+ return tokens[1..tokens.size], enum
50
+ end
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..tokens.size]
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..tokens.size]
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
+
77
+ def parse_struct(tokens)
78
+ struct_fields = {}
79
+ while tokens.size >= 2 and tokens[1] == :colon
80
+ name = tokens[0]
81
+ tokens, type = self.parse(tokens[2..tokens.size])
82
+ struct_fields[name.to_sym] = type
83
+ end
84
+ return tokens[1..tokens.size], struct_fields
85
+ end
86
+
87
+ def parse(tokens)
88
+ while tokens.size > 0
89
+ if tokens[0] == "type"
90
+ name = tokens[1]
91
+ tokens, type = self.parse(tokens[2..tokens.size])
92
+ @definitions[name.to_sym] = type
93
+ elsif tokens[0] == "map"
94
+ raise SchemaParsingException.new("Map must be followed by a '[' eg. map[string]data") if tokens[1] != :open_brace
95
+ tokens, map_from_type = parse(tokens[2..tokens.size])
96
+ raise SchemaParsingException.new("Map to type must be followed by a ']' eg. map[string]data") if tokens[0] != :close_brace
97
+ tokens, map_to_type = parse(tokens[1..tokens.size])
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..tokens.size], Bare.DataFixedLen(tokens[2])
103
+ elsif tokens[0] == "enum"
104
+ name = tokens[1]
105
+ raise SchemaParsingException.new("Enum must be followed by a '{'") if tokens[2] != :open_block
106
+ tokens, enum = parse_enum(tokens[3..tokens.size])
107
+ @definitions[name.to_sym] = 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..tokens.size])
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..tokens.size], Bare.Optional(optional_type)
113
+ elsif tokens[0] == :open_brace
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..tokens.size])
118
+ return tokens, Bare.ArrayFixedLen(arr_type, size)
119
+ else
120
+ tokens, arr_type = parse(tokens[2..tokens.size])
121
+ return tokens, Bare.Array(arr_type)
122
+ end
123
+ elsif tokens[0] == :open_paren
124
+ tokens, union_hash = parse_union(tokens[1..tokens.size])
125
+ raise SchemaParsingException.new("Union must be followed by a ')'") if tokens[0] != :close_paren
126
+ return tokens[1..tokens.size], Bare.Union(union_hash)
127
+ elsif tokens[0] == :open_block
128
+ tokens, struct_fields = parse_struct(tokens[1..tokens.size])
129
+ strct = Bare.Struct(struct_fields)
130
+ return tokens, strct
131
+ elsif @primitives.include?(tokens[0])
132
+ type = @primitives[tokens[0]]
133
+ return tokens[1..tokens.size], type
134
+ elsif @definitions.keys.include?(tokens[0].to_sym) # User defined type
135
+ return tokens[1..tokens.size], @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.size], tokens[0].to_sym
138
+ else
139
+ raise SchemaParsingException.new("Unable to parse token: #{tokens[0]}")
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+
146
+ def parser(tokens, definitions = {})
147
+ parser = Parser.new
148
+ parser.parse(tokens)
149
+ return parser.definitions
150
+ end
data/lib/types.rb CHANGED
@@ -3,16 +3,26 @@ 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
13
+
9
14
  # Types which are always equivalent to another instantiation of themselves
10
15
  # Eg. Uint.new == Uint.new
11
16
  # But Union.new(types1) != Union.new(types2)
12
17
  # since unions could have different sets of types
18
+
13
19
  def ==(other)
14
20
  self.class == other.class
15
21
  end
22
+
23
+ def finalize_references(schema)
24
+ end
25
+
16
26
  end
17
27
 
18
28
  class Int < BarePrimitive
@@ -22,11 +32,11 @@ class BareTypes
22
32
  mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
23
33
  return Uint.new.encode(mappedInteger)
24
34
  end
35
+
25
36
  def decode(msg)
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] }
37
+ value, rest = Uint.new.decode(msg)
38
+ value = value.odd? ? (value + 1) / -2 : value / 2
39
+ return value, rest
30
40
  end
31
41
  end
32
42
 
@@ -34,17 +44,19 @@ class BareTypes
34
44
  def encode(msg)
35
45
  return "".b
36
46
  end
47
+
37
48
  def decode(msg)
38
- return {value: nil, rest: msg}
49
+ return nil, msg
39
50
  end
40
51
  end
41
52
 
42
53
  class F32 < BarePrimitive
43
54
  def encode(msg)
44
- return [msg].pack("e")
55
+ [msg].pack("e")
45
56
  end
57
+
46
58
  def decode(msg)
47
- return {value: msg.unpack("e")[0], rest: msg[4..msg.size]}
59
+ return msg.unpack("e")[0], msg[4..msg.size]
48
60
  end
49
61
  end
50
62
 
@@ -52,8 +64,9 @@ class BareTypes
52
64
  def encode(msg)
53
65
  return [msg].pack("E")
54
66
  end
67
+
55
68
  def decode(msg)
56
- return {value: msg.unpack("E")[0], rest: msg[8..msg.size]}
69
+ return msg.unpack("E")[0], msg[8..msg.size]
57
70
  end
58
71
  end
59
72
 
@@ -69,11 +82,11 @@ class BareTypes
69
82
  bytes << encodedString
70
83
  return bytes
71
84
  end
85
+
72
86
  def decode(msg)
73
- output = Uint.new.decode(msg)
74
- 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] }
87
+ strLen, rest = Uint.new.decode(msg)
88
+ string = rest[0..strLen - 1]
89
+ return string.force_encoding("utf-8"), rest[strLen..rest.size]
77
90
  end
78
91
  end
79
92
 
@@ -82,6 +95,16 @@ class BareTypes
82
95
  return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
83
96
  end
84
97
 
98
+ def finalize_references(schema)
99
+ return if @finalized
100
+ @finalized = true
101
+ if @optionalType.is_a?(Symbol)
102
+ @optionalType = schema[@optionalType]
103
+ else
104
+ @optionalType.finalize_references(schema)
105
+ end
106
+ end
107
+
85
108
  def optionalType
86
109
  @optionalType
87
110
  end
@@ -95,7 +118,7 @@ class BareTypes
95
118
  if msg.nil?
96
119
  return "\x00".b
97
120
  else
98
- bytes = "\xFF".b
121
+ bytes = "\x01".b
99
122
  bytes << @optionalType.encode(msg)
100
123
  return bytes
101
124
  end
@@ -103,7 +126,7 @@ class BareTypes
103
126
 
104
127
  def decode(msg)
105
128
  if msg.unpack("C")[0] == 0
106
- return {value: nil, rest: msg[1..msg.size]}
129
+ return nil, msg[1..msg.size]
107
130
  else
108
131
  return @optionalType.decode(msg[1..msg.size])
109
132
  end
@@ -115,9 +138,23 @@ class BareTypes
115
138
  return otherType.class == BareTypes::Map && otherType.from == @from && otherType.to == @to
116
139
  end
117
140
 
141
+ def finalize_references(schema)
142
+ return if @finalized
143
+ @finalized = true
144
+ if @from.is_a?(Symbol)
145
+ @to = schema[@to]
146
+ else
147
+ @to.finalize_references(schema)
148
+ end
149
+ end
150
+
118
151
  def initialize(fromType, toType)
119
152
  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)
153
+ if !fromType.class.ancestors.include?(BarePrimitive) ||
154
+ fromType.is_a?(BareTypes::Data) ||
155
+ fromType.is_a?(BareTypes::DataFixedLen)
156
+ raise MapKeyError("Map keys must use a primitive type which is not data or data<length>.")
157
+ end
121
158
  @from = fromType
122
159
  @to = toType
123
160
  end
@@ -141,24 +178,34 @@ class BareTypes
141
178
 
142
179
  def decode(msg)
143
180
  hash = Hash.new
144
- output = Uint.new.decode(msg)
145
- mapSize = output[:value]
181
+ mapSize, rest = Uint.new.decode(msg)
146
182
  (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
- hash[key] = output[:value]
183
+ key, rest = @from.decode(rest)
184
+ value, rest = @to.decode(rest)
185
+ hash[key] = value
152
186
  end
153
- return {value: hash, rest: output[:rest]}
187
+ return hash, rest
154
188
  end
155
189
  end
156
190
 
157
191
  class Union < BarePrimitive
192
+
158
193
  def intToType
159
194
  @intToType
160
195
  end
161
196
 
197
+ def finalize_references(schema)
198
+ return if @finalized
199
+ @finalized = true
200
+ @intToType.keys.each do |key|
201
+ if @intToType[key].is_a?(Symbol)
202
+ @intToType[key] = schema[@intToType[key]]
203
+ else
204
+ @intToType[key].finalize_references(schema)
205
+ end
206
+ end
207
+ end
208
+
162
209
  def ==(otherType)
163
210
  return false unless otherType.is_a?(BareTypes::Union)
164
211
  @intToType.each do |int, type|
@@ -194,11 +241,10 @@ class BareTypes
194
241
  end
195
242
 
196
243
  def decode(msg)
197
- unionTypeInt = Uint.new.decode(msg)
198
- int = unionTypeInt[:value]
244
+ int, rest = Uint.new.decode(msg)
199
245
  type = @intToType[int]
200
- value = type.decode(unionTypeInt[:rest])
201
- return {value: {value: value[:value], type: type}, rest: value[:rest]}
246
+ value, rest = type.decode(rest)
247
+ return {value: value, type: type}, rest
202
248
  end
203
249
  end
204
250
 
@@ -211,21 +257,31 @@ class BareTypes
211
257
  return @length
212
258
  end
213
259
 
260
+ def finalize_references(schema)
261
+ end
262
+
214
263
  def initialize(length)
215
264
  raise MinimumSizeError("DataFixedLen must have a length greater than 0, got: #{length.inspect}") if length < 1
216
265
  @length = length
217
266
  end
218
267
 
219
268
  def encode(msg)
220
- return msg
269
+ if msg.size != @length
270
+ raise FixedDataSizeWrong.new("Message is not proper sized for DataFixedLen should have been #{@length} but was #{msg.size}")
271
+ end
272
+ msg
221
273
  end
222
274
 
223
275
  def decode(msg)
224
- return {value: msg[0..@length], rest: msg[@length..msg.size]}
276
+ return msg[0..@length], msg[@length..msg.size]
225
277
  end
226
278
  end
227
279
 
228
280
  class Data < BarePrimitive
281
+
282
+ def finalize_references(schema)
283
+ end
284
+
229
285
  def encode(msg)
230
286
  bytes = Uint.new.encode(msg.size)
231
287
  bytes << msg
@@ -233,14 +289,16 @@ class BareTypes
233
289
  end
234
290
 
235
291
  def decode(msg)
236
- output = Uint.new.decode(msg)
237
- rest = output[:rest]
238
- dataSize = output[:value]
239
- return {value: rest[0..dataSize], rest: rest[dataSize..rest.size]}
292
+ dataSize, rest = Uint.new.decode(msg)
293
+ return rest[0..dataSize - 1], rest[dataSize..rest.size]
240
294
  end
241
295
  end
242
296
 
243
297
  class Uint < BarePrimitive
298
+
299
+ def finalize_references(schema)
300
+ end
301
+
244
302
  def encode(msg)
245
303
  bytes = "".b
246
304
  _get_next_7_bits_as_byte(msg, 128) do |byte|
@@ -259,7 +317,7 @@ class BareTypes
259
317
  end
260
318
 
261
319
  def decode(msg)
262
- ints = msg.unpack("CCCCCCCCC")
320
+ ints = msg.unpack("CCCCCCCC")
263
321
  relevantInts = []
264
322
  i = 0
265
323
  while ints[i] & 0b10000000 == 128
@@ -271,7 +329,7 @@ class BareTypes
271
329
  relevantInts.each_with_index do |int, idx|
272
330
  sum += int << (idx * 7)
273
331
  end
274
- return {value: sum, rest: msg[(i + 1)..msg.size]}
332
+ return sum, msg[(i + 1)..msg.size]
275
333
  end
276
334
  end
277
335
 
@@ -281,7 +339,7 @@ class BareTypes
281
339
  end
282
340
 
283
341
  def decode(msg)
284
- return {value: msg[0].unpack("C")[0], rest: msg[1..msg.size]}
342
+ return msg[0].unpack("C")[0], msg[1..msg.size]
285
343
  end
286
344
  end
287
345
 
@@ -291,7 +349,7 @@ class BareTypes
291
349
  end
292
350
 
293
351
  def decode(msg)
294
- return {value: msg.unpack("v")[0], rest: msg[2..msg.size]}
352
+ return msg.unpack("v")[0], msg[2..msg.size]
295
353
  end
296
354
  end
297
355
 
@@ -301,7 +359,7 @@ class BareTypes
301
359
  end
302
360
 
303
361
  def decode(msg)
304
- return {value: msg.unpack("V")[0], rest: msg[4..msg.size]}
362
+ return msg.unpack("V")[0], msg[4..msg.size]
305
363
  end
306
364
  end
307
365
 
@@ -311,7 +369,7 @@ class BareTypes
311
369
  end
312
370
 
313
371
  def decode(msg)
314
- return {value: msg.unpack("Q")[0], rest: [8..msg.size]}
372
+ return msg.unpack("Q")[0], msg[8..msg.size]
315
373
  end
316
374
  end
317
375
 
@@ -321,7 +379,7 @@ class BareTypes
321
379
  end
322
380
 
323
381
  def decode(msg)
324
- return {value: msg[0].unpack("c")[0], rest: msg[1..msg.size]}
382
+ return msg[0].unpack("c")[0], msg[1..msg.size]
325
383
  end
326
384
  end
327
385
 
@@ -331,7 +389,7 @@ class BareTypes
331
389
  end
332
390
 
333
391
  def decode(msg)
334
- return {value: msg.unpack('s<')[0], rest: msg[2..msg.size]}
392
+ return msg.unpack('s<')[0], msg[2..msg.size]
335
393
  end
336
394
  end
337
395
 
@@ -341,7 +399,7 @@ class BareTypes
341
399
  end
342
400
 
343
401
  def decode(msg)
344
- return {value: msg.unpack('l<')[0], rest: msg[4..msg.size]}
402
+ return msg.unpack('l<')[0], msg[4..msg.size]
345
403
  end
346
404
  end
347
405
 
@@ -351,7 +409,7 @@ class BareTypes
351
409
  end
352
410
 
353
411
  def decode(msg)
354
- return {value: msg.unpack('q<')[0], rest: msg[8..msg.size]}
412
+ return msg.unpack('q<')[0], msg[8..msg.size]
355
413
  end
356
414
  end
357
415
 
@@ -361,11 +419,16 @@ class BareTypes
361
419
  end
362
420
 
363
421
  def decode(msg)
364
- return {value: msg == "\x00\x00" ? false : true, rest: msg[1..msg.size]}
422
+ return (msg == "\x00\x00" ? false : true), msg[1..msg.size]
365
423
  end
366
424
  end
367
425
 
368
426
  class Struct < BaseType
427
+
428
+ def [](key)
429
+ return @mapping[key]
430
+ end
431
+
369
432
  def ==(otherType)
370
433
  return false unless otherType.class == BareTypes::Struct
371
434
  @mapping.each do |k, v|
@@ -374,16 +437,31 @@ class BareTypes
374
437
  return true
375
438
  end
376
439
 
440
+ def finalize_references(schema)
441
+ return if @finalized
442
+ @finalized = true
443
+ @mapping.each do |key, val|
444
+ if val.is_a?(Symbol)
445
+ @mapping[key] = schema[val]
446
+ else
447
+ val.finalize_references(schema)
448
+ end
449
+ end
450
+ end
451
+
377
452
  def mapping
378
453
  @mapping
379
454
  end
380
455
 
381
456
  def initialize(symbolToType)
382
- # Mapping from symbols to Bare types
457
+ # Mapping from symbols to Bare types (or possibly symbols before finalizing)
383
458
  symbolToType.keys.each do |k|
384
- raise BareException("Struct keys must be symbols") unless k.is_a?(Symbol)
385
- raise BareException("Struct values must be a BareTypes::TYPE\nInstead got: #{symbolToType[k].inspect}") unless symbolToType[k].class.ancestors.include?(BaseType)
386
- 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
459
+ raise BareException.new("Struct keys must be symbols") unless k.is_a?(Symbol)
460
+ if (!symbolToType[k].class.ancestors.include?(BaseType) && !symbolToType[k].is_a?(Symbol))
461
+ raise BareException.new("Struct values must be a BareTypes::TYPE or a symbol with the same
462
+ name as a user defined type\nInstead got: #{symbolToType[k].inspect}")
463
+ end
464
+ 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
387
465
  end
388
466
  raise("Struct must have at least one field") if symbolToType.keys.size == 0
389
467
  @mapping = symbolToType
@@ -392,7 +470,7 @@ class BareTypes
392
470
  def encode(msg)
393
471
  bytes = "".b
394
472
  @mapping.keys.each do |symbol|
395
- raise SchemaMismatch("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
473
+ raise SchemaMismatch.new("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
396
474
  bytes << @mapping[symbol].encode(msg[symbol])
397
475
  end
398
476
  return bytes
@@ -402,11 +480,10 @@ class BareTypes
402
480
  hash = Hash.new
403
481
  rest = msg
404
482
  @mapping.keys.each do |symbol|
405
- output = @mapping[symbol].decode(rest)
406
- hash[symbol] = output[:value]
407
- rest = output[:rest]
483
+ value, rest = @mapping[symbol].decode(rest)
484
+ hash[symbol] = value
408
485
  end
409
- return {value: hash, rest: rest}
486
+ return hash, rest
410
487
  end
411
488
  end
412
489
 
@@ -419,8 +496,18 @@ class BareTypes
419
496
  return @type
420
497
  end
421
498
 
499
+ def finalize_references(schema)
500
+ return if @finalized
501
+ @finalized = true
502
+ if @type.is_a?(Symbol)
503
+ @type = schema[@type]
504
+ else
505
+ @type.finalize_references(schema)
506
+ end
507
+ end
508
+
422
509
  def initialize(type)
423
- raise VoidUsedOutsideTaggedSet("Void types may only be used as members of the set of types in a tagged union.") if type.class == BareTypes::Void
510
+ 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
424
511
  @type = type
425
512
  end
426
513
 
@@ -433,17 +520,16 @@ class BareTypes
433
520
  end
434
521
 
435
522
  def decode(msg)
436
- output = Uint.new.decode(msg)
437
523
  arr = []
438
- arrayLen = output[:value]
524
+ arrayLen, rest = Uint.new.decode(msg)
439
525
  lastSize = msg.size + 1 # Make sure msg size monotonically decreasing
440
526
  (arrayLen - 1).downto(0) do
441
- output = @type.decode(output[:rest])
442
- arr << output[:value]
443
- break if output[:rest].nil? || output[:rest].size == 0 || lastSize <= output[:rest].size
444
- lastSize = output[:rest].size
527
+ arrVal, rest = @type.decode(rest)
528
+ arr << arrVal
529
+ break if rest.nil? || rest.size == 0 || lastSize <= rest.size
530
+ lastSize = rest.size
445
531
  end
446
- return {value: arr, rest: output[:rest]}
532
+ return arr, rest
447
533
  end
448
534
  end
449
535
 
@@ -452,11 +538,21 @@ class BareTypes
452
538
  return otherType.class == BareTypes::ArrayFixedLen && otherType.type == @type && otherType.size == @size
453
539
  end
454
540
 
541
+ def finalize_references(schema)
542
+ return if @finalized
543
+ @finalized = true
544
+ if @type.is_a?(Symbol)
545
+ @type = schema[@type]
546
+ else
547
+ @type.finalize_references(schema)
548
+ end
549
+ end
550
+
455
551
  def initialize(type, size)
456
552
  @type = type
457
553
  @size = size
458
- raise VoidUsedOutsideTaggedSet("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
459
- raise MinimumSizeError("FixedLenArray size must be > 0") if size < 1
554
+ raise VoidUsedOutsideTaggedSet.new("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
555
+ raise MinimumSizeError.new("FixedLenArray size must be > 0") if size < 1
460
556
  end
461
557
 
462
558
  def type
@@ -468,7 +564,7 @@ class BareTypes
468
564
  end
469
565
 
470
566
  def encode(arr)
471
- raise SchemaMismatch("This FixLenArray is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
567
+ raise SchemaMismatch.new("This FixLenArray is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
472
568
  bytes = ""
473
569
  arr.each do |item|
474
570
  bytes << @type.encode(item)
@@ -476,15 +572,13 @@ class BareTypes
476
572
  return bytes
477
573
  end
478
574
 
479
- def decode(msg)
575
+ def decode(rest)
480
576
  array = []
481
- rest = msg
482
577
  @size.times do
483
- output = @type.decode(rest)
484
- rest = output[:rest]
485
- array << output[:value]
578
+ arrVal, rest = @type.decode(rest)
579
+ array << arrVal
486
580
  end
487
- return {value: array, rest: rest}
581
+ return array, rest
488
582
  end
489
583
  end
490
584
 
@@ -497,6 +591,10 @@ class BareTypes
497
591
  return true
498
592
  end
499
593
 
594
+
595
+ def finalize_references(schema)
596
+ end
597
+
500
598
  def intToVal
501
599
  @intToVal
502
600
  end
@@ -504,9 +602,9 @@ class BareTypes
504
602
  def initialize(source)
505
603
  @intToVal = {}
506
604
  @valToInt = {}
507
- raise BareException("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
508
- raise BareException("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
509
- raise BareException("Enum must have unique values") if source.values.to_set.size != source.values.size
605
+ raise BareException.new("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
606
+ raise BareException.new("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
607
+ raise EnumValueError.new("Enum must have unique values") if source.values.to_set.size != source.values.size
510
608
  source.each do |k, v|
511
609
  raise("Enum keys must be positive integers") if k < 0
512
610
  @intToVal[k.to_i] = v
@@ -515,17 +613,15 @@ class BareTypes
515
613
  end
516
614
 
517
615
  def encode(msg)
518
- raise SchemaMismatch("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
616
+ raise SchemaMismatch.new("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
519
617
  integerRep = @valToInt[msg]
520
618
  encoded = BareTypes::Uint.new.encode(integerRep)
521
619
  return encoded
522
620
  end
523
621
 
524
622
  def decode(msg)
525
- output = BareTypes::Uint.new.decode(msg)
526
- value = output[:value]
527
- rest = output[:rest]
528
- return {value: @intToVal[value], rest: rest}
623
+ value, rest = BareTypes::Uint.new.decode(msg)
624
+ return @intToVal[value], rest
529
625
  end
530
626
  end
531
627
  end
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.0.0
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Tracy-Amoroso
@@ -10,7 +10,8 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2020-10-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Implements the bare message encoding and DSL in ruby
13
+ description: The first implementation of the BARE (Binary Application Record Encoding)
14
+ in Ruby. Includes schema parsing and compatibility tests.
14
15
  email: n8@u.northwestern.edu
15
16
  executables: []
16
17
  extensions: []
@@ -18,8 +19,10 @@ extra_rdoc_files: []
18
19
  files:
19
20
  - "./lib/bare-rb.rb"
20
21
  - "./lib/exceptions.rb"
22
+ - "./lib/lexer.rb"
23
+ - "./lib/parser.rb"
21
24
  - "./lib/types.rb"
22
- homepage: https://none.none
25
+ homepage: https://github.com/n8ta/bare-rb
23
26
  licenses:
24
27
  - MIT
25
28
  metadata: {}