cauterize 0.0.1.pre12 → 0.0.1.pre13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/example/Cauterize +0 -2
  4. data/lib/cauterize/builders/c/buildable.rb +7 -0
  5. data/lib/cauterize/builders/c/builtin.rb +4 -0
  6. data/lib/cauterize/builders/c/composite.rb +8 -0
  7. data/lib/cauterize/builders/c/enumeration.rb +8 -4
  8. data/lib/cauterize/builders/c/fixed_array.rb +11 -2
  9. data/lib/cauterize/builders/c/group.rb +26 -1
  10. data/lib/cauterize/builders/c/scalar.rb +4 -0
  11. data/lib/cauterize/builders/c/variable_array.rb +17 -3
  12. data/lib/cauterize/builders/cs/builtin.rb +1 -1
  13. data/lib/cauterize/builders/cs/fixed_array.rb +3 -1
  14. data/lib/cauterize/builders/ruby/builtin.rb +1 -1
  15. data/lib/cauterize/builders/ruby/composite.rb +10 -7
  16. data/lib/cauterize/builders/ruby/enumeration.rb +9 -9
  17. data/lib/cauterize/builders/ruby/fixed_array.rb +4 -4
  18. data/lib/cauterize/builders/ruby/group.rb +9 -9
  19. data/lib/cauterize/builders/ruby/scalar.rb +3 -3
  20. data/lib/cauterize/builders/ruby/variable_array.rb +5 -5
  21. data/lib/cauterize/c_builder.rb +6 -0
  22. data/lib/cauterize/enumeration.rb +4 -14
  23. data/lib/cauterize/representation.rb +32 -0
  24. data/lib/cauterize/ruby_builder.rb +7 -5
  25. data/lib/cauterize/variable_array.rb +3 -12
  26. data/lib/cauterize/version.rb +1 -1
  27. data/spec/base_type_spec.rb +2 -2
  28. data/spec/builders/c/group_spec.rb +21 -0
  29. data/spec/builders/c/variable_array_spec.rb +2 -4
  30. data/spec/builders/cs/fixed_array_spec.rb +2 -1
  31. data/spec/builders/cs/variable_array_spec.rb +0 -1
  32. data/spec/c_builder_spec.rb +22 -2
  33. data/spec/cs_builder_spec.rb +0 -2
  34. data/spec/doc_builder_spec.rb +0 -2
  35. data/spec/ruby_builder_spec.rb +5 -2
  36. data/spec/ruby_generated_spec.rb +735 -0
  37. data/spec/support/spec_sample_model.rb +1 -3
  38. data/spec/variable_array_spec.rb +5 -19
  39. data/support/cs/src/CauterizeFixedArrayFormatter.cs +27 -9
  40. data/support/cs/src/CauterizeVariableArrayFormatter.cs +28 -11
  41. data/support/ruby/src/cauterize_ruby_baseclasses.rb +297 -176
  42. data/support/ruby/src/cauterize_ruby_builtins.rb +121 -95
  43. metadata +25 -39
@@ -17,7 +17,6 @@ module Cauterize
17
17
  end
18
18
 
19
19
  Cauterize.variable_array(:int8_list) do |a|
20
- a.size_type :uint8
21
20
  a.array_type :int8
22
21
  a.array_size 200
23
22
  end
@@ -53,9 +52,8 @@ module Cauterize
53
52
  end
54
53
 
55
54
  Cauterize.variable_array(:int8_list) do |a|
56
- a.size_type :uint8
57
55
  a.array_type :int8
58
- a.array_size 200
56
+ a.array_size 2000
59
57
  end
60
58
 
61
59
  Cauterize.composite(:two_things) do |t|
@@ -61,26 +61,12 @@ module Cauterize
61
61
  end
62
62
 
63
63
  describe :size_type do
64
- it "defines the type to use to encode the array size" do
65
- Cauterize.scalar(:uint16_t)
66
- @a.size_type :uint16_t
67
- @a.instance_variable_get(:@size_type).name.should == :uint16_t
68
- end
69
-
70
- it "raises an error if the type doesn't eixst" do
71
- lambda { @a.size_type :uintLOL_t }.should raise_error /does not correspond to a type/
72
- end
64
+ it "determines the type used to encode the array size" do
65
+ @a.array_size 30000
66
+ @a.size_type.name.should == :uint16
73
67
 
74
- it "raises an error if the type isn't an scalar" do
75
- Cauterize.scalar(:uint32_t) { |t| t.type_name(:uint32) }
76
- Cauterize.enumeration(:lol)
77
- lambda { @a.size_type :lol }.should raise_error /is not a built-in or scalar/
78
- end
79
-
80
- it "is the defined type if no argument is passed" do
81
- s = Cauterize.scalar(:uint32_t)
82
- @a.size_type :uint32_t
83
- @a.size_type.should be s
68
+ @a.array_size 10
69
+ @a.size_type.name.should == :uint8
84
70
  end
85
71
  end
86
72
  end
@@ -11,16 +11,27 @@ namespace Cauterize
11
11
  }
12
12
  public override object Deserialize(Stream serializationStream, Type t)
13
13
  {
14
- var ret = t.GetConstructor(new Type[] {}).Invoke(new object[] {});
15
14
  var arrayField = t.BaseType.GetField("_data", BindingFlags.NonPublic | BindingFlags.Instance);
16
- var array = (Array)arrayField.GetValue(ret);
17
15
  var arrayType = arrayField.FieldType.GetElementType();
18
- var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
19
- for (var i = 0; i < array.Length; i++)
16
+ if (arrayType == typeof (Byte))
20
17
  {
21
- array.SetValue(subFormatter.Deserialize(serializationStream, arrayType), i);
18
+ var arraySize = (int) t.GetField("MySize").GetValue(null);
19
+ var arrayData = new byte[arraySize];
20
+ serializationStream.Read(arrayData, 0, arraySize);
21
+ var ret = t.GetConstructor(new Type[] {typeof (Byte[])}).Invoke(new object[] {arrayData});
22
+ return ret;
23
+ }
24
+ else
25
+ {
26
+ var ret = t.GetConstructor(new Type[] {}).Invoke(new object[] {});
27
+ var array = (Array)arrayField.GetValue(ret);
28
+ var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
29
+ for (var i = 0; i < array.Length; i++)
30
+ {
31
+ array.SetValue(subFormatter.Deserialize(serializationStream, arrayType), i);
32
+ }
33
+ return ret;
22
34
  }
23
- return ret;
24
35
  }
25
36
 
26
37
  public override void Serialize(Stream serializationStream, object obj)
@@ -29,10 +40,17 @@ namespace Cauterize
29
40
  var arrayField = t.BaseType.GetField("_data", BindingFlags.NonPublic | BindingFlags.Instance);
30
41
  var array = (Array)arrayField.GetValue(obj);
31
42
  var arrayType = arrayField.FieldType.GetElementType();
32
- var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
33
- for (var i = 0; i < array.Length; i++)
43
+ if (arrayType == typeof (Byte))
44
+ {
45
+ serializationStream.Write((byte[]) array, 0, array.Length);
46
+ }
47
+ else
34
48
  {
35
- subFormatter.Serialize(serializationStream, array.GetValue(i));
49
+ var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
50
+ for (var i = 0; i < array.Length; i++)
51
+ {
52
+ subFormatter.Serialize(serializationStream, array.GetValue(i));
53
+ }
36
54
  }
37
55
  }
38
56
  }
@@ -14,20 +14,30 @@ namespace Cauterize
14
14
 
15
15
  public override object Deserialize(Stream serializationStream, Type t)
16
16
  {
17
+ var arrayField = t.BaseType.GetField("_data", BindingFlags.NonPublic | BindingFlags.Instance);
18
+ var arrayType = arrayField.FieldType.GetElementType();
17
19
  var sizeType = (Type) t.GetField("SizeType").GetValue(null);
18
20
  var sizeFormatter = _typeFormatterFactory.GetFormatter(sizeType);
19
21
  var rawSize = sizeFormatter.Deserialize(serializationStream, sizeType);
20
22
  var arraySize = PrimitiveSupport.TypeToInt(rawSize);
21
- var ret = t.GetConstructor(new Type[] {typeof (int)}).Invoke(new object[] {arraySize});
22
- var arrayField = t.BaseType.GetField("_data", BindingFlags.NonPublic | BindingFlags.Instance);
23
- var array = (Array)arrayField.GetValue(ret);
24
- var arrayType = arrayField.FieldType.GetElementType();
25
- var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
26
- for (var i = 0; i < arraySize; i++)
23
+ if (arrayType == typeof (Byte))
27
24
  {
28
- array.SetValue(subFormatter.Deserialize(serializationStream, arrayType), i);
25
+ var arrayData = new byte[arraySize];
26
+ serializationStream.Read(arrayData, 0, arraySize);
27
+ var ret = t.GetConstructor(new Type[] {typeof (Byte[])}).Invoke(new object[] {arrayData});
28
+ return ret;
29
+ }
30
+ else
31
+ {
32
+ var ret = t.GetConstructor(new Type[] {typeof (int)}).Invoke(new object[] {arraySize});
33
+ var array = (Array)arrayField.GetValue(ret);
34
+ var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
35
+ for (var i = 0; i < arraySize; i++)
36
+ {
37
+ array.SetValue(subFormatter.Deserialize(serializationStream, arrayType), i);
38
+ }
39
+ return ret;
29
40
  }
30
- return ret;
31
41
  }
32
42
 
33
43
  public override void Serialize(Stream serializationStream, object obj)
@@ -39,10 +49,17 @@ namespace Cauterize
39
49
  var sizeFormatter = _typeFormatterFactory.GetFormatter(sizeType);
40
50
  sizeFormatter.Serialize(serializationStream, PrimitiveSupport.IntToType(sizeType, array.Length));
41
51
  var arrayType = arrayField.FieldType.GetElementType();
42
- var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
43
- for (var i = 0; i < array.Length; i++)
52
+ if (arrayType == typeof (Byte))
53
+ {
54
+ serializationStream.Write((byte[])array, 0, array.Length);
55
+ }
56
+ else
44
57
  {
45
- subFormatter.Serialize(serializationStream, array.GetValue(i));
58
+ var subFormatter = _typeFormatterFactory.GetFormatter(arrayType);
59
+ for (var i = 0; i < array.Length; i++)
60
+ {
61
+ subFormatter.Serialize(serializationStream, array.GetValue(i));
62
+ }
46
63
  }
47
64
  }
48
65
  }
@@ -1,246 +1,367 @@
1
1
  require 'stringio'
2
2
 
3
- class CauterizeData
4
- def self.construct(x)
5
- if x.is_a? CauterizeData
6
- raise "Invalid Type: was #{x.class}, expected #{self.name}" if not x.is_a?(self)
3
+ module CauterizeRuby
4
+ class Data
5
+ @@specializers = Hash.new { |h, k| k }
6
+
7
+ def self.set_specializer(c)
8
+ @@specializers[self] = c
9
+ end
10
+
11
+ def self.do_construct(x)
12
+ if x.is_a? Data
13
+ raise "Invalid Type: was #{x.class}, expected #{self}" if not x.is_a?(self)
14
+ x
15
+ else
16
+ self.new x
17
+ end
18
+ end
19
+
20
+ def self.construct(x)
21
+ @@specializers[self].do_construct(x)
22
+ end
23
+
24
+ def self.unpackio(x)
25
+ @@specializers[self].do_unpackio(x)
26
+ end
27
+
28
+ def pack
29
+ x = ""
30
+ packio(x)
7
31
  x
8
- else
9
- self.new x
10
32
  end
11
- end
12
33
 
13
- def self.unpack(x)
14
- self.unpackio(StringIO.new(x))
15
- end
16
- end
34
+ def self.unpack(x)
35
+ self.unpackio(StringIO.new(x))
36
+ end
17
37
 
18
- class CauterizeBuiltin < CauterizeData
19
- def initialize(val)
20
- raise "Out of range value" if not in_range(val)
21
- @val = val
22
- end
23
- def to_ruby
24
- @val
25
- end
26
- end
38
+ def ==(other)
39
+ (self <=> other) == 0
40
+ end
27
41
 
28
- class CauterizeBuiltinInteger < CauterizeBuiltin
29
- def initialize(val)
30
- super(val.to_i)
42
+ #this promotes 'other' to a cauterize type if it's not one already
43
+ # this way 'cmp' can always assume 'other' is of the same type
44
+ def <=>(other)
45
+ cmp(self.class.construct(other))
46
+ end
31
47
  end
32
48
 
33
- def to_i
34
- @val
49
+ class Builtin < Data
50
+ def initialize(val)
51
+ @val = val
52
+ end
53
+ def to_ruby
54
+ @val
55
+ end
56
+ # for builtins max_size == min_size
57
+ def self.min_size() max_size end
58
+ def num_bytes() self.class::max_size end
35
59
  end
36
- end
37
60
 
38
- class CauterizeBuiltinFloat < CauterizeBuiltin
39
- def initialize(val)
40
- super(val.to_f)
41
- end
61
+ class BuiltinInteger < Builtin
62
+ def initialize(val)
63
+ #this will always set @val to a regular ruby Fixnum
64
+ super(val.to_i)
65
+ end
42
66
 
43
- def to_f
44
- @val
45
- end
46
- end
67
+ def to_i
68
+ @val
69
+ end
47
70
 
48
- class CauterizeBuiltinBool < CauterizeBuiltin
49
- def initialize(val)
50
- super((val)? true : false)
71
+ def to_f
72
+ @val.to_f
73
+ end
51
74
  end
52
- end
53
75
 
76
+ class BuiltinFloat < Builtin
77
+ def initialize(val)
78
+ #this will always set @val to a regular ruby float
79
+ super(val.to_f)
80
+ end
54
81
 
55
- class CauterizeScalar < CauterizeData
56
- def initialize(val)
57
- @val = self.class.builtin.construct val
58
- end
82
+ def to_f
83
+ @val
84
+ end
59
85
 
60
- def to_ruby
61
- @val.to_ruby
86
+ def to_i
87
+ @val.to_i
88
+ end
62
89
  end
63
90
 
64
- def pack
65
- @val.pack
91
+ class BuiltinBool < Builtin
92
+ def initialize(val)
93
+ #this will always set @val to a regular ruby boolean value
94
+ super((val)? true : false)
95
+ end
66
96
  end
67
97
 
68
- def self.unpackio(str)
69
- self.new self.builtin.unpackio(str)
70
- end
71
- end
72
98
 
73
- class CauterizeArray < CauterizeData
74
- def to_ruby
75
- @elems.map{|e| e.to_ruby}
76
- end
99
+ class Scalar < Data
100
+ attr_reader :builtin
101
+ def initialize(val)
102
+ # @builtin is going to be some form of Builtin
103
+ @builtin = self.class.builtin.construct val
104
+ raise "#{self.class}: Out of range value: #{@builtin.to_ruby}, for #{self.class}" if not @builtin.in_range(@builtin.to_ruby)
105
+ end
77
106
 
78
- def to_string
79
- to_ruby.to_a.pack("C*")
80
- end
81
- end
107
+ def to_ruby
108
+ @builtin.to_ruby
109
+ end
82
110
 
83
- class CauterizeFixedArray < CauterizeArray
84
- attr_reader :elems
111
+ def to_i
112
+ @builtin.to_i
113
+ end
85
114
 
86
- def initialize(elems)
87
- @elems = elems.map { |e| self.class.elem_type.construct(e) }
88
- raise "Invalid length" if @elems.length != self.class.length
89
- end
115
+ def to_f
116
+ @builtin.to_f
117
+ end
90
118
 
91
- def pack
92
- @elems.inject("") { |sum, n| sum + n.pack }
93
- end
119
+ def packio(x)
120
+ @builtin.packio(x)
121
+ end
122
+
123
+ def self.do_unpackio(str)
124
+ self.new self.builtin.unpackio(str)
125
+ end
94
126
 
95
- def self.unpackio(str)
96
- self.new (1..self.length).map { self.elem_type.unpackio(str) }
127
+ def cmp(other)
128
+ @builtin <=> other.builtin
129
+ end
130
+
131
+ def num_bytes() @builtin.num_bytes end
132
+ def self.max_size() builtin::max_size end
133
+ def self.min_size() builtin::min_size end
97
134
  end
98
- end
99
135
 
136
+ class Array < Data
100
137
 
101
- class CauterizeVariableArray < CauterizeArray
102
- attr_reader :length
103
- attr_reader :elems
138
+ include Enumerable
104
139
 
105
- def initialize(elems)
106
- @elems = elems.map { |e| self.class.elem_type.construct(e) }
107
- @length = self.class.size_type.new @elems.length
108
- raise "Invalid length" if @elems.length > self.class.max_length
109
- end
140
+ def initialize(elems)
141
+ if elems.is_a? String
142
+ # a special case for strings
143
+ initialize_arr(elems.unpack("C*"))
144
+ else
145
+ initialize_arr(elems)
146
+ end
147
+ end
110
148
 
111
- def pack
112
- @length.pack + @elems.inject("") { |sum, n| sum + n.pack }
113
- end
149
+ def each
150
+ elems.each do |e|
151
+ yield e
152
+ end
153
+ end
114
154
 
115
- def self.unpackio(str)
116
- length = self.size_type.unpackio(str)
117
- self.new (1..length.to_i).map { self.elem_type.unpackio(str) }
155
+ def to_ruby
156
+ @elems.map{|e| e.to_ruby}
157
+ end
158
+
159
+ def to_string
160
+ to_ruby.to_a.pack("C*")
161
+ end
162
+
163
+ def cmp(other)
164
+ elems <=> other.elems
165
+ end
118
166
  end
119
- end
120
167
 
168
+ class FixedArray < Array
169
+ attr_reader :elems
121
170
 
122
- class CauterizeComposite < CauterizeData
123
- attr_reader :fields
171
+ def initialize_arr(elems)
172
+ @elems = elems.map { |e| self.class.elem_type.construct(e) }
173
+ raise "#{self.class}: Invalid length: #{@elems.length}, expected: #{self.class.length}" if @elems.length != self.class.length
174
+ end
124
175
 
125
- def initialize(field_values)
126
- missing_keys = self.class.fields.keys - field_values.keys
127
- extra_keys = field_values.keys - self.class.fields.keys
128
- raise "missing fields #{missing_keys}" if not missing_keys.empty?
129
- raise "extra fields #{extra_keys}" if not extra_keys.empty?
130
- @fields = Hash[field_values.map do |field_name, value|
131
- [field_name, self.class.fields[field_name].construct(value)]
132
- end]
133
- end
176
+ def packio(x)
177
+ elems.each do |e|
178
+ e.packio(x)
179
+ end
180
+ end
134
181
 
135
- def to_ruby
136
- Hash[@fields.map{|name, value| [name, value.to_ruby]}]
137
- end
182
+ def self.do_unpackio(str)
183
+ self.new (1..self.length).map { self.elem_type.unpackio(str) }
184
+ end
138
185
 
139
- def pack
140
- @fields.values.inject("") { |sum, v| sum + v.pack }
186
+ def num_bytes() elems.reduce(0) {|sum, e| sum + e.num_bytes} end
187
+ def self.max_size() length * elem_type::max_size end
188
+ def self.min_size() length * elem_type::min_size end
141
189
  end
142
190
 
143
- def self.unpackio(str)
144
- self.new Hash[self.fields.keys.map do |k|
145
- [k, self.fields[k].unpackio(str)]
146
- end]
147
- end
148
191
 
149
- alias orig_method_missing method_missing
192
+ class VariableArray < Array
193
+ attr_reader :length
194
+ attr_reader :elems
195
+
196
+ def initialize_arr(elems)
197
+ @elems = elems.map { |e| self.class.elem_type.construct(e) }
198
+ @length = self.class.size_type.new @elems.length
199
+ raise "#{self.class}: Invalid length: #{@elems.length}, max length is: #{self.class.max_length}" if @elems.length > self.class.max_length
200
+ end
150
201
 
151
- def method_missing(m, *args, &block)
152
- if fields[m]
153
- fields[m]
154
- else
155
- orig_method_missing(m, *args, &block)
202
+ def packio(x)
203
+ @length.packio(x)
204
+ @elems.each do |e|
205
+ e.packio(x)
206
+ end
156
207
  end
208
+
209
+ def self.do_unpackio(str)
210
+ length = self.size_type.unpackio(str)
211
+ self.new (1..length.to_i).map { self.elem_type.unpackio(str) }
212
+ end
213
+
214
+ def num_bytes() length.num_bytes + elems.reduce(0) {|sum, e| sum + e.num_bytes} end
215
+ def self.max_size() size_type::max_size + (max_length * elem_type::max_size) end
216
+ def self.min_size() size_type::min_size end
157
217
  end
158
- end
159
218
 
160
219
 
161
- class CauterizeEnumeration < CauterizeData
162
- attr_reader :field_name
220
+ class Composite < Data
221
+ attr_reader :fields
163
222
 
164
- def initialize(field_name)
165
- raise "Invalid field name #{field_name}" if not self.class.fields.keys.include?(field_name)
166
- @field_name = field_name
167
- end
223
+ def initialize(field_values)
224
+ missing_keys = self.class.fields.keys - field_values.keys
225
+ extra_keys = field_values.keys - self.class.fields.keys
226
+ bad_init = !extra_keys.empty? || !missing_keys.empty?
227
+ raise "#{self.class}: Invalid initialization params, missing fields: #{missing_keys}, extra fields: #{extra_keys}" if bad_init
228
+ @fields = Hash[self.class.fields.keys.map do |field_name|
229
+ [field_name, self.class.fields[field_name].construct(field_values[field_name])]
230
+ end]
231
+ end
168
232
 
169
- def to_ruby
170
- @field_name
171
- end
233
+ def to_ruby
234
+ Hash[@fields.map{|name, value| [name, value.to_ruby]}]
235
+ end
172
236
 
173
- def to_i() self.class.fields[@field_name] end
237
+ def packio(x)
238
+ @fields.values.each do |v|
239
+ v.packio(x)
240
+ end
241
+ end
174
242
 
175
- def pack
176
- self.class.repr_type.construct(self.class.fields[@field_name]).pack
177
- end
243
+ def self.do_unpackio(str)
244
+ self.new Hash[self.fields.keys.map do |k|
245
+ [k, self.fields[k].unpackio(str)]
246
+ end]
247
+ end
178
248
 
179
- def self.from_int(i)
180
- raise "Invalid enumeration value #{i.to_i}" if not self.fields.values.include? i.to_i
181
- self.new(self.fields.invert[i.to_i])
182
- end
249
+ def cmp(other)
250
+ fields.values <=> other.fields.values
251
+ end
252
+
253
+ def num_bytes
254
+ fields.values.reduce(0) {|sum, v| sum + v.num_bytes}
255
+ end
183
256
 
184
- def self.unpackio(str)
185
- self.from_int(self.repr_type.unpackio(str).to_i)
257
+ def self.max_size
258
+ fields.values.reduce(0) {|sum, v| sum + v::max_size}
259
+ end
260
+
261
+ def self.min_size
262
+ fields.values.reduce(0) {|sum, v| sum + v::min_size}
263
+ end
186
264
  end
187
- end
188
265
 
189
266
 
190
- class CauterizeGroup < CauterizeData
191
- attr_reader :tag
192
- attr_reader :data
267
+ class Enumeration < Data
268
+ attr_reader :field_name
193
269
 
194
- def to_ruby
195
- if data.nil?
196
- { tag: tag_field_name }
197
- else
198
- { tag: tag_field_name,
199
- data: data.to_ruby }
270
+ def initialize(field_name)
271
+ raise "#{self.class}: Invalid field name: #{field_name}, Valid field names are: #{self.class.fields.keys}" if not self.class.fields.keys.include?(field_name)
272
+ @field_name = field_name
200
273
  end
201
- end
202
274
 
203
- def tag_field_name
204
- self.class.from_tag_field_name(@tag.field_name)
205
- end
275
+ def to_ruby
276
+ @field_name
277
+ end
206
278
 
207
- def self.tag_from_field_name(field_name)
208
- self.tag_type.construct((self.tag_prefix + field_name.to_s).to_sym)
209
- end
279
+ def to_i() self.class.fields[@field_name] end
210
280
 
211
- def self.from_tag_field_name(tag_name)
212
- t = tag_name.to_s
213
- t.slice!(self.tag_prefix)
214
- t.to_sym
215
- end
216
-
217
- def initialize(h)
218
- @tag = self.class.tag_from_field_name(h[:tag])
281
+ def packio(x)
282
+ self.class.repr_type.construct(self.class.fields[@field_name]).packio(x)
283
+ end
219
284
 
220
- field_class = self.class.fields[tag_field_name]
221
- if field_class.nil?
222
- @data = nil
223
- else
224
- @data = field_class.construct(h[:data])
285
+ def self.from_int(i)
286
+ raise "#{self}: Invalid enumeration value: #{i.to_i}" if not self.fields.values.include? i.to_i
287
+ self.new(self.fields.invert[i.to_i])
288
+ end
289
+
290
+ def self.do_unpackio(str)
291
+ self.from_int(self.repr_type.unpackio(str).to_i)
225
292
  end
226
- end
227
293
 
228
- def pack
229
- if @data.nil?
230
- @tag.pack
231
- else
232
- @tag.pack + @data.pack
294
+ def cmp(other)
295
+ to_i <=> other.to_i
233
296
  end
297
+
298
+ def num_bytes() self.class.repr_type::max_size end
299
+ def self.max_size() repr_type::max_size end
300
+ def self.min_size() repr_type::min_size end
234
301
  end
235
302
 
236
- def self.unpackio(str)
237
- tag = self.tag_type.unpackio(str)
238
- field_name = self.from_tag_field_name(tag.field_name)
239
- data_type = self.fields[field_name]
240
- if data_type.nil?
241
- self.new({ tag: field_name })
242
- else
243
- self.new({ tag: field_name, data: data_type.unpackio(str) })
303
+
304
+ class Group < Data
305
+ attr_reader :tag
306
+ attr_reader :data
307
+
308
+ def to_ruby
309
+ if data.nil?
310
+ { tag: tag_field_name }
311
+ else
312
+ { tag: tag_field_name,
313
+ data: data.to_ruby }
314
+ end
315
+ end
316
+
317
+ def tag_field_name
318
+ self.class.from_tag_field_name(@tag.field_name)
319
+ end
320
+
321
+ def self.tag_from_field_name(field_name)
322
+ self.tag_type.construct((self.tag_prefix + field_name.to_s).to_sym)
323
+ end
324
+
325
+ def self.from_tag_field_name(tag_name)
326
+ t = tag_name.to_s
327
+ t.slice!(self.tag_prefix)
328
+ t.to_sym
329
+ end
330
+
331
+ def initialize(h)
332
+ @tag = self.class.tag_from_field_name(h[:tag])
333
+ field_class = self.class.fields[tag_field_name]
334
+ @data = (field_class.nil?) ? nil : field_class.construct(h[:data])
335
+ end
336
+
337
+ def packio(x)
338
+ @tag.packio(x)
339
+ @data.packio(x) unless @data.nil?
340
+ end
341
+
342
+ def self.do_unpackio(str)
343
+ tag = self.tag_type.unpackio(str)
344
+ field_name = self.from_tag_field_name(tag.field_name)
345
+ data_type = self.fields[field_name]
346
+ if data_type.nil?
347
+ self.new({ tag: field_name })
348
+ else
349
+ self.new({ tag: field_name, data: data_type.unpackio(str) })
350
+ end
244
351
  end
352
+
353
+ def cmp(other)
354
+ r = (tag <=> other.tag)
355
+ if r == 0
356
+ data <=> other.data
357
+ else
358
+ r
359
+ end
360
+ end
361
+
362
+ def num_bytes() tag.num_bytes + ((data.nil?) ? 0 : data.num_bytes) end
363
+
364
+ def self.max_size() tag_type::max_size + fields.values.map{|v| (v.nil?) ? 0 : v::max_size}.max end
365
+ def self.min_size() tag_type::min_size + fields.values.map{|v| (v.nil?) ? 0 : v::min_size}.min end
245
366
  end
246
367
  end