cauterize 0.0.1.pre12 → 0.0.1.pre13

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.
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