scale.rb 0.2.17 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Cargo.lock +8 -4
  4. data/Cargo.toml +2 -3
  5. data/Dockerfile +4 -1
  6. data/Gemfile.lock +23 -21
  7. data/README.md +44 -1
  8. data/Rakefile +6 -0
  9. data/exe/scale +49 -0
  10. data/lib/helper.rb +19 -4
  11. data/lib/metadata/metadata.rb +27 -17
  12. data/lib/metadata/metadata_v0.rb +24 -20
  13. data/lib/metadata/metadata_v1.rb +13 -9
  14. data/lib/metadata/metadata_v10.rb +2 -2
  15. data/lib/metadata/metadata_v11.rb +2 -2
  16. data/lib/metadata/metadata_v12.rb +9 -8
  17. data/lib/metadata/metadata_v13.rb +161 -0
  18. data/lib/metadata/metadata_v2.rb +2 -2
  19. data/lib/metadata/metadata_v3.rb +2 -2
  20. data/lib/metadata/metadata_v4.rb +21 -11
  21. data/lib/metadata/metadata_v5.rb +21 -11
  22. data/lib/metadata/metadata_v6.rb +9 -9
  23. data/lib/metadata/metadata_v7.rb +26 -15
  24. data/lib/metadata/metadata_v8.rb +9 -9
  25. data/lib/metadata/metadata_v9.rb +2 -2
  26. data/lib/scale.rb +40 -339
  27. data/lib/scale/base.rb +175 -93
  28. data/lib/scale/block.rb +10 -10
  29. data/lib/scale/trie.rb +1 -1
  30. data/lib/scale/types.rb +139 -40
  31. data/lib/scale/version.rb +1 -1
  32. data/lib/scale_bytes.rb +63 -0
  33. data/lib/substrate_client.rb +11 -8
  34. data/lib/type_builder.rb +280 -0
  35. data/lib/type_registry.rb +91 -0
  36. data/lib/type_registry/crab.json +676 -595
  37. data/lib/type_registry/darwinia.json +730 -554
  38. data/lib/type_registry/default.json +3 -2
  39. data/lib/type_registry/pangolin.json +771 -0
  40. data/scale.gemspec +1 -0
  41. data/scripts/mmr_root_to_sign.rb +10 -0
  42. data/src/lib.rs +80 -25
  43. metadata +25 -10
  44. data/lib/type_registry/edgeware.json +0 -124
  45. data/lib/type_registry/joystream.json +0 -49
  46. data/lib/type_registry/kulupu.json +0 -15
  47. data/lib/type_registry/plasm.json +0 -89
  48. data/lib/type_registry/robonomics.json +0 -39
  49. data/lib/type_registry/westend.json +0 -63
  50. data/src/storage_key.rs +0 -41
@@ -1,7 +1,7 @@
1
1
  module Scale
2
2
  module Types
3
3
  class MetadataV9
4
- include SingleValue
4
+ include Base
5
5
  attr_accessor :call_index, :event_index
6
6
 
7
7
  def initialize(value)
@@ -11,7 +11,7 @@ module Scale
11
11
  end
12
12
 
13
13
  def self.decode(scale_bytes)
14
- modules = Scale::Types.type_of("Vec<MetadataV8Module>").decode(scale_bytes).value
14
+ modules = Scale::Types.get("Vec<MetadataV8Module>").decode(scale_bytes).value
15
15
 
16
16
  value = {
17
17
  magicNumber: 1_635_018_093,
data/lib/scale.rb CHANGED
@@ -5,6 +5,11 @@ require "common"
5
5
  require "json"
6
6
  require "singleton"
7
7
 
8
+ require "scale_bytes"
9
+
10
+ require "type_registry"
11
+ require "type_builder"
12
+
8
13
  require "scale/base"
9
14
  require "scale/types"
10
15
  require "scale/block"
@@ -24,361 +29,36 @@ require "metadata/metadata_v9"
24
29
  require "metadata/metadata_v10"
25
30
  require "metadata/metadata_v11"
26
31
  require "metadata/metadata_v12"
32
+ require "metadata/metadata_v13"
27
33
 
28
34
  require "substrate_client"
29
35
  require "logger"
30
36
  require "helper"
31
37
 
32
- class String
33
- def upcase_first
34
- self.sub(/\S/, &:upcase)
35
- end
36
-
37
- def camelize2
38
- self.split('_').collect(&:upcase_first).join
39
- end
40
-
41
- def underscore2
42
- self.gsub(/::/, '/').
43
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
44
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
45
- tr("-", "_").
46
- downcase
47
- end
48
- end
49
-
50
38
  module Scale
51
- class Error < StandardError; end
52
-
53
- class TypeRegistry
54
- include Singleton
55
-
56
- # init by load, and will not change
57
- attr_reader :spec_name, :types
58
- attr_reader :versioning, :custom_types # optional
59
-
60
- # will change by different spec version
61
- attr_accessor :spec_version # optional
62
- attr_accessor :metadata
63
-
64
- def load(spec_name: nil, custom_types: nil)
65
- @spec_name = nil
66
- @types = nil
67
- @versioning = nil
68
- @custom_types = nil
39
+ class ScaleError < StandardError; end
40
+ class TypeBuildError < ScaleError; end
41
+ class BadDataError < ScaleError; end
42
+ class TypeRegistryNotLoadYet < ScaleError; end
43
+ class StorageInputTypeError < ScaleError; end
69
44
 
70
- default_types, _, _ = load_chain_spec_types("default")
45
+ module Types
46
+ class << self
47
+ attr_accessor :debug, :logger
48
+ end
71
49
 
72
- if spec_name
50
+ def self.check_types
51
+ TypeRegistry.instance.all_types.keys.each do |key|
73
52
  begin
74
- @spec_name = spec_name
75
- spec_types, @versioning, @spec_version = load_chain_spec_types(spec_name)
76
- @types = default_types.merge(spec_types)
53
+ type = self.get(key)
77
54
  rescue => ex
78
- puts "There is no types json file named #{spec_name}"
79
- @types = default_types
55
+ puts "[[ERROR]] #{key}: #{ex}"
80
56
  end
81
- else
82
- @spec_name = "default"
83
- @types = default_types
84
57
  end
85
-
86
- self.custom_types = custom_types
87
58
  true
88
59
  end
89
60
 
90
- def get(type_name)
91
- raise "Types not loaded" if @types.nil?
92
-
93
- all_types = {}.merge(@types)
94
-
95
- if @spec_version && @versioning
96
- @versioning.each do |item|
97
- if @spec_version >= item["runtime_range"][0] &&
98
- ( item["runtime_range"][1].nil? || @spec_version <= item["runtime_range"][1] )
99
- all_types.merge!(item["types"])
100
- end
101
- end
102
- end
103
-
104
- all_types.merge!(@custom_types) if @custom_types
105
-
106
- type = type_traverse(type_name, all_types)
107
-
108
- Scale::Types.constantize(type)
109
- end
110
-
111
- def custom_types=(custom_types)
112
- @custom_types = custom_types.stringify_keys if (not custom_types.nil?) && custom_types.class.name == "Hash"
113
- end
114
-
115
- private
116
-
117
- def load_chain_spec_types(spec_name)
118
- file = File.join File.expand_path("../..", __FILE__), "lib", "type_registry", "#{spec_name}.json"
119
- json_string = File.open(file).read
120
- json = JSON.parse(json_string)
121
-
122
- runtime_id = json["runtime_id"]
123
-
124
- [json["types"], json["versioning"], runtime_id]
125
- end
126
-
127
- def type_traverse(type, types)
128
- type = rename(type) if type.class == ::String
129
- if types.has_key?(type) && types[type] != type
130
- type_traverse(types[type], types)
131
- else
132
- type
133
- end
134
- end
135
61
  end
136
-
137
- # TODO: == implement
138
-
139
- class Bytes
140
- attr_reader :data, :bytes
141
- attr_reader :offset
142
-
143
- def initialize(data)
144
- if (data.class == Array) && data.is_byte_array?
145
- @bytes = data
146
- elsif (data.class == String) && data.start_with?("0x") && (data.length % 2 == 0)
147
- arr = data[2..].scan(/../).map(&:hex)
148
- @bytes = arr
149
- else
150
- raise "Provided data is not valid"
151
- end
152
-
153
- @data = data
154
- @offset = 0
155
- end
156
-
157
- def reset_offset
158
- @offset = 0
159
- end
160
-
161
- def get_next_bytes(length)
162
- result = @bytes[@offset...@offset + length]
163
- if result.length < length
164
- str = @data[(2 + @offset * 2)..]
165
- str = str.length > 40 ? (str[0...40]).to_s + "..." : str
166
- raise "No enough data: #{str}, expect length: #{length}, but #{result.length}"
167
- end
168
- @offset += length
169
- result
170
- rescue RangeError => ex
171
- puts "length: #{length}"
172
- puts ex.message
173
- puts ex.backtrace
174
- end
175
-
176
- def get_remaining_bytes
177
- @bytes[offset..]
178
- end
179
-
180
- def to_hex_string
181
- @bytes.bytes_to_hex
182
- end
183
-
184
- def to_bin_string
185
- @bytes.bytes_to_bin
186
- end
187
-
188
- def to_ascii
189
- @bytes[0...offset].pack("C*") + "<================================>" + @bytes[offset..].pack("C*")
190
- end
191
-
192
- def ==(other)
193
- bytes == other.bytes && offset == other.offset
194
- end
195
-
196
- def to_s
197
- green(@bytes[0...offset].bytes_to_hex) + yellow(@bytes[offset..].bytes_to_hex[2..])
198
- end
199
- end
200
-
201
- class TypesLoader
202
- def self.load(filename)
203
- path = File.join File.dirname(__FILE__), "types", filename
204
- content = File.open(path).read
205
- result = JSON.parse content
206
-
207
- types = result["default"]
208
- types.each do |name, body|
209
- if body.class == String
210
- target_type = "Scale::Types::#{body}"
211
- klass = Class.new(target_type.constantize2) do
212
- end
213
- elsif body.class == Hash
214
- if body["type"] == "struct"
215
- struct_params = {}
216
- body["type_mapping"].each do |mapping|
217
- struct_params[mapping[0].to_sym] = mapping[1]
218
- end
219
- klass = Class.new do
220
- end
221
- klass.send(:include, Scale::Types::Struct)
222
- klass.send(:items, struct_params)
223
- Scale::Types.const_set name, klass
224
- elsif body["type"] = "enum"
225
- klass = Class.new do
226
- end
227
- klass.send(:include, Scale::Types::Enum)
228
- if body["type_mapping"]
229
- struct_params = {}
230
- body["type_mapping"].each do |mapping|
231
- struct_params[mapping[0].to_sym] = mapping[1]
232
- end
233
- klass.send(:items, struct_params)
234
- else
235
- klass.send(:values, body["value_list"])
236
- end
237
- Scale::Types.const_set name, klass
238
- end
239
- end
240
- end
241
- end
242
- end
243
-
244
- module Types
245
- def self.list
246
- TypeRegistry.instance.types
247
- end
248
-
249
- def self.get(type_name)
250
- TypeRegistry.instance.get(type_name)
251
- end
252
-
253
- def self.constantize(type)
254
- if type.class == ::String
255
- type_of(type.strip)
256
- else
257
- if type["type"] == "enum" && type.has_key?("type_mapping")
258
- type_of("Enum", type["type_mapping"].to_h)
259
- elsif type["type"] == "enum" && type.has_key?("value_list")
260
- type_of("Enum", type["value_list"])
261
- elsif type["type"] == "struct"
262
- type_of("Struct", type["type_mapping"].to_h)
263
- elsif type["type"] == "set"
264
- type_of("Set", type["value_list"])
265
- end
266
- end
267
- end
268
-
269
- def self.type_of(type_string, values = nil)
270
- if type_string.end_with?(">")
271
- type_strs = type_string.scan(/^([^<]*)<(.+)>$/).first
272
- type_str = type_strs.first
273
- inner_type_str = type_strs.last
274
-
275
- if type_str == "Vec" || type_str == "Option"
276
- klass = Class.new do
277
- include Scale::Types.type_of(type_str)
278
- inner_type inner_type_str
279
- end
280
- name = "#{type_str}<#{inner_type_str.camelize2}>_#{klass.object_id}"
281
- Scale::Types.const_set fix(name), klass
282
- else
283
- raise "#{type_str} not support inner type: #{type_string}"
284
- end
285
- elsif type_string.start_with?("(") && type_string.end_with?(")") # tuple
286
- # TODO: add nested tuple support
287
- types_with_inner_type = type_string[1...-1].scan(/([A-Za-z]+<[^>]*>)/).first
288
-
289
- types_with_inner_type&.each do |type_str|
290
- new_type_str = type_str.tr(",", ";")
291
- type_string = type_string.gsub(type_str, new_type_str)
292
- end
293
-
294
- type_strs = type_string[1...-1].split(",").map do |type_str|
295
- type_str.strip.tr(";", ",")
296
- end
297
-
298
- klass = Class.new do
299
- include Scale::Types::Tuple
300
- inner_types *type_strs
301
- end
302
- name = "Tuple_Of_#{type_strs.map(&:camelize2).join("_")}_#{klass.object_id}"
303
- Scale::Types.const_set fix(name), klass
304
- else
305
- if type_string == "Enum"
306
- # TODO: combine values to items
307
- klass = Class.new do
308
- include Scale::Types::Enum
309
- if values.class == ::Hash
310
- items values
311
- else
312
- values(*values)
313
- end
314
- end
315
- name = values.class == ::Hash ? values.values.map(&:camelize2).join("_") : values.map(&:camelize2).join("_")
316
- name = "Enum_Of_#{name}_#{klass.object_id}"
317
- Scale::Types.const_set fix(name), klass
318
- elsif type_string == "Struct"
319
- klass = Class.new do
320
- include Scale::Types::Struct
321
- items values
322
- end
323
- name = "Struct_Of_#{values.values.map(&:camelize2).join("_")}_#{klass.object_id}"
324
- Scale::Types.const_set fix(name), klass
325
- elsif type_string == "Set"
326
- klass = Class.new do
327
- include Scale::Types::Set
328
- items values, 1
329
- end
330
- name = "Set_Of_#{values.keys.map(&:camelize2).join("_")}_#{klass.object_id}"
331
- Scale::Types.const_set fix(name), klass
332
- else
333
- type_name = (type_string.start_with?("Scale::Types::") ? type_string : "Scale::Types::#{type_string}")
334
- begin
335
- type_name.constantize2
336
- rescue NameError => e
337
- puts "#{type_string} is not defined"
338
- end
339
- end
340
- end
341
- end
342
- end
343
-
344
- end
345
-
346
- def fix(name)
347
- name
348
- .gsub("<", "˂").gsub(">", "˃")
349
- .gsub("(", "⁽").gsub(")", "⁾")
350
- .gsub(" ", "").gsub(",", "‚")
351
- .gsub(":", "։")
352
- end
353
-
354
- def rename(type)
355
- type = type.gsub("T::", "")
356
- .gsub("<T>", "")
357
- .gsub("<T as Trait>::", "")
358
- .delete("\n")
359
- .gsub("EventRecord<Event, Hash>", "EventRecord")
360
- .gsub(/(u)(\d+)/, 'U\2')
361
- return "Bool" if type == "bool"
362
- return "Null" if type == "()"
363
- return "String" if type == "Vec<u8>"
364
- return "Compact" if type == "Compact<u32>" || type == "Compact<U32>"
365
- return "Address" if type == "<Lookup as StaticLookup>::Source"
366
- return "Vec<Address>" if type == "Vec<<Lookup as StaticLookup>::Source>"
367
- return "Compact" if type == "<Balance as HasCompact>::Type"
368
- return "Compact" if type == "<BlockNumber as HasCompact>::Type"
369
- return "Compact" if type == "Compact<Balance>"
370
- return "Compact" if type == "Compact<BlockNumber>"
371
- return "CompactMoment" if type == "<Moment as HasCompact>::Type"
372
- return "CompactMoment" if type == "Compact<Moment>"
373
- return "InherentOfflineReport" if type == "<InherentOfflineReport as InherentOfflineReport>::Inherent"
374
- return "AccountData" if type == "AccountData<Balance>"
375
-
376
- if type =~ /\[U\d+; \d+\]/
377
- byte_length = type.scan(/\[U\d+; (\d+)\]/).first.first.to_i
378
- return "VecU8Length#{byte_length}"
379
- end
380
-
381
- type
382
62
  end
383
63
 
384
64
  def green(text)
@@ -389,6 +69,24 @@ def yellow(text)
389
69
  "\033[33m#{text}\033[0m"
390
70
  end
391
71
 
72
+ class String
73
+ def upcase_first
74
+ self.sub(/\S/, &:upcase)
75
+ end
76
+
77
+ def camelize2
78
+ self.split('_').collect(&:upcase_first).join
79
+ end
80
+
81
+ def underscore2
82
+ self.gsub(/::/, '/').
83
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
84
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
85
+ tr("-", "_").
86
+ downcase
87
+ end
88
+ end
89
+
392
90
  # https://www.ruby-forum.com/t/question-about-hex-signed-int/125510/4
393
91
  # machine bit length:
394
92
  # machine_byte_length = ['foo'].pack('p').size
@@ -426,3 +124,6 @@ class ::Hash
426
124
  Hash[h]
427
125
  end
428
126
  end
127
+
128
+ Scale::Types.debug = false
129
+ Scale::Types.logger = Logger.new(STDOUT)
data/lib/scale/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Scale
2
2
  module Types
3
3
 
4
- module SingleValue
4
+ module Base
5
5
  attr_reader :value
6
6
 
7
7
  def initialize(value)
@@ -9,62 +9,74 @@ module Scale
9
9
  end
10
10
 
11
11
  def ==(other)
12
- value == other.value
12
+ self.class == other.class && self.value == other.value
13
13
  end
14
14
 
15
15
  def to_human
16
16
  if @value.class == ::Hash
17
17
  @value.transform_values do |v|
18
- if v.class.included_modules.include?(SingleValue)
18
+ if v.class.included_modules.include?(Base)
19
19
  v.to_human
20
20
  else
21
21
  v
22
22
  end
23
- end
23
+ end.transform_keys(&:to_sym)
24
24
  elsif @value.class == ::Array
25
25
  @value.map do |v|
26
- if v.class.included_modules.include?(SingleValue)
26
+ if v.class.included_modules.include?(Base)
27
27
  v.to_human
28
28
  else
29
29
  v
30
30
  end
31
31
  end
32
+ elsif @value.class.include?(Base)
33
+ @value.to_human
32
34
  else
33
35
  @value
34
36
  end
35
37
  end
38
+
39
+ module ClassMethods
40
+ def inherited(child)
41
+ child.const_set(:TYPE_NAME, child.name)
42
+ end
43
+ end
44
+
45
+ def self.included(base)
46
+ base.extend(ClassMethods)
47
+ base.const_set(:TYPE_NAME, base.name)
48
+ end
36
49
  end
37
50
 
38
- # value: one of nil, false, true, scale object
51
+ # if value is bool, see type `OptionBool` in types.rb
39
52
  module Option
40
- include SingleValue
53
+ include Base
41
54
 
42
55
  module ClassMethods
43
56
  def decode(scale_bytes)
57
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
44
58
  byte = scale_bytes.get_next_bytes(1)
45
59
  if byte == [0]
60
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
46
61
  new(nil)
47
62
  elsif byte == [1]
48
- if self::INNER_TYPE_STR == "boolean"
49
- new(false)
50
- else
51
- # big process
52
- value = Scale::Types.get(self::INNER_TYPE_STR).decode(scale_bytes)
53
- new(value)
54
- end
55
- elsif byte == [2]
56
- if self::INNER_TYPE_STR == "boolean"
57
- new(true)
58
- else
59
- raise "bad data"
60
- end
63
+ # big process
64
+ type =
65
+ if self::INNER_TYPE.class == ::String
66
+ Scale::Types.get(self::INNER_TYPE)
67
+ else
68
+ self::INNER_TYPE
69
+ end
70
+ value = type.decode(scale_bytes)
71
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
72
+ new(value)
61
73
  else
62
- raise "bad data"
74
+ raise BadDataError.new("Bad scale data for #{self::TYPE_NAME}")
63
75
  end
64
76
  end
65
77
 
66
- def inner_type(type_str)
67
- const_set(:INNER_TYPE_STR, type_str)
78
+ def inner_type(type)
79
+ const_set(:INNER_TYPE, type)
68
80
  end
69
81
  end
70
82
 
@@ -77,21 +89,21 @@ module Scale
77
89
  if value.nil?
78
90
  "00"
79
91
  else
80
- return "02" if value.class == TrueClass && value === true
81
- return "01" if value.class == FalseClass && value === false
82
92
  "01" + value.encode
83
93
  end
84
94
  end
85
95
  end
86
96
 
87
97
  module FixedWidthInt
88
- include SingleValue
98
+ include Base
89
99
 
90
100
  module ClassMethods
91
101
  def decode(scale_bytes)
102
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
92
103
  bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
93
104
  bit_length = bytes.length.to_i * 8
94
105
  value = bytes.reverse.bytes_to_hex.to_i(16).to_signed(bit_length)
106
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
95
107
  new(value)
96
108
  end
97
109
  end
@@ -111,16 +123,21 @@ module Scale
111
123
  end
112
124
 
113
125
  module FixedWidthUInt
114
- include SingleValue
126
+ include Base
115
127
 
116
128
  module ClassMethods
117
129
  attr_accessor :byte_length
118
130
 
119
131
  def decode(scale_bytes)
132
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
120
133
  bytes = scale_bytes.get_next_bytes self::BYTE_LENGTH
121
134
  bytes_reversed = bytes.reverse
122
135
  hex = bytes_reversed.reduce("0x") { |hex, byte| hex + byte.to_s(16).rjust(2, "0") }
123
- new(hex.to_i(16))
136
+ result = new(hex.to_i(16))
137
+
138
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
139
+
140
+ result
124
141
  end
125
142
  end
126
143
 
@@ -139,68 +156,85 @@ module Scale
139
156
  end
140
157
 
141
158
  module Struct
142
- include SingleValue
159
+ include Base
143
160
  # new(1.to_u32, U32(69))
144
161
  module ClassMethods
162
+ def inherited(child)
163
+ child.const_set(:TYPE_NAME, child.name)
164
+ end
165
+
145
166
  def decode(scale_bytes)
146
- item_values = self::ITEM_TYPE_STRS.map do |item_type_str|
147
- type = Scale::TypeRegistry.instance.get(item_type_str)
148
- type.decode(scale_bytes)
167
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
168
+
169
+ # item_values:
170
+ # {
171
+ # a: ...,
172
+ # b: ...
173
+ # }
174
+ item_values = {}
175
+ self::ITEMS.each_pair do |item_name, item_type|
176
+ if item_type.class == ::String
177
+ item_type = Scale::Types.get(item_type)
178
+ end
179
+ item_values[item_name] = item_type.decode(scale_bytes)
149
180
  end
150
181
 
151
- value = {}
152
- self::ITEM_NAMES.zip(item_values) do |attr, val|
153
- value[attr] = val
154
- end
182
+ # value = {}
183
+ # self::ITEM_NAMES.zip(item_values) do |attr, val|
184
+ # value[attr] = val
185
+ # end
155
186
 
156
- result = new(value)
157
- value.each_pair do |attr, val|
158
- result.send "#{attr}=", val
187
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
188
+
189
+ result = new(item_values)
190
+ item_values.each_pair do |item_name, item_value|
191
+ result.send "#{item_name.to_s}=", item_value
159
192
  end
193
+
160
194
  result
161
195
  end
162
196
 
163
- def items(items)
164
- attr_names = []
165
- attr_type_strs = []
166
-
167
- items.each_pair do |attr_name, attr_type_str|
168
- attr_names << attr_name.to_s.gsub("-", "")
169
- attr_type_strs << attr_type_str
170
- end
171
-
172
- const_set(:ITEM_NAMES, attr_names)
173
- const_set(:ITEM_TYPE_STRS, attr_type_strs)
174
- attr_accessor *attr_names
197
+ # items(a: Scale::Types::Type1, b: "Type2")
198
+ def items(**items)
199
+ const_set(:ITEMS, items)
200
+ item_names = items.keys
201
+ attr_accessor *item_names
175
202
  end
176
203
  end
177
204
 
178
205
  def self.included(base)
179
206
  base.extend ClassMethods
207
+ base.const_set(:TYPE_NAME, base.name)
180
208
  end
181
209
 
182
210
  def encode
183
- [].tap do |result|
184
- value.each_pair do |attr_name, attr_value|
185
- result << attr_value.encode
186
- end
211
+ value.values.map do |item_value|
212
+ item_value.encode
187
213
  end.join
188
214
  end
189
215
  end
190
216
 
191
217
  module Tuple
192
- include SingleValue
218
+ include Base
193
219
 
194
220
  module ClassMethods
195
221
  def decode(scale_bytes)
196
- values = self::TYPE_STRS.map do |type_str|
197
- Scale::Types.get(type_str).decode(scale_bytes)
222
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
223
+
224
+ values = self::INNER_TYPES.map do |type|
225
+ if type.class == ::String
226
+ type = Scale::Types.get(type)
227
+ end
228
+ type.decode(scale_bytes)
198
229
  end
230
+
231
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
199
232
  new(values)
200
233
  end
201
234
 
202
- def inner_types(*type_strs)
203
- const_set(:TYPE_STRS, type_strs)
235
+ # inner_types Scale::Types::U8, "U8"
236
+ def inner_types(*inner_types)
237
+ const_set(:INNER_TYPES, inner_types)
204
238
  end
205
239
  end
206
240
 
@@ -214,38 +248,46 @@ module Scale
214
248
  end
215
249
 
216
250
  module Enum
217
- include SingleValue
251
+ include Base
252
+
253
+ attr_accessor :index
218
254
 
219
255
  module ClassMethods
220
256
  def decode(scale_bytes)
257
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
221
258
  index = scale_bytes.get_next_bytes(1)[0]
222
- if const_defined? "ITEM_TYPE_STRS"
223
- item_type_str = self::ITEM_TYPE_STRS[index]
224
- raise "There is no such member with index #{index} for enum #{self}" if item_type_str.nil?
225
- value = Scale::Types.get(item_type_str).decode(scale_bytes)
226
- else
259
+ if const_defined? "ITEMS"
260
+ type = self::ITEMS.values[index]
261
+ if type.class == ::String
262
+ type = Scale::Types.get(type)
263
+ end
264
+ value = type.decode(scale_bytes)
265
+ elsif const_defined? "INNER_TYPES"
266
+ type = self::INNER_TYPES[index]
267
+ if type.class == ::String
268
+ type = Scale::Types.get(type)
269
+ end
270
+ value = type.decode(scale_bytes)
271
+ else # VALUES
227
272
  value = self::VALUES[index]
228
273
  end
229
- new(value)
274
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
275
+ result = new(value)
276
+ result.index = index
277
+ result
230
278
  end
231
279
 
232
- def items(items)
233
- if items.class == ::Hash
234
- attr_names = []
235
- attr_type_strs = []
236
-
237
- items.each_pair do |attr_name, attr_type_str|
238
- attr_names << attr_name
239
- attr_type_strs << attr_type_str
240
- end
280
+ # inner_types(Scale::Types::Compact, "Hex")
281
+ def inner_types(*inner_types)
282
+ const_set(:INNER_TYPES, inner_types)
283
+ end
241
284
 
242
- const_set(:ITEM_NAMES, attr_names)
243
- const_set(:ITEM_TYPE_STRS, attr_type_strs)
244
- elsif items.class == ::Array
245
- const_set(:ITEM_TYPE_STRS, items)
246
- end
285
+ # items(Item1: Scale::Types::Compact, Item2: "Hex")
286
+ def items(**items)
287
+ const_set(:ITEMS, items)
247
288
  end
248
289
 
290
+ # [1, "hello"]
249
291
  def values(*values)
250
292
  const_set(:VALUES, values)
251
293
  end
@@ -256,17 +298,17 @@ module Scale
256
298
  end
257
299
 
258
300
  def encode
259
- if self.class.const_defined? "ITEM_NAMES"
260
- value_type_str = value.class.to_s.split("::").last.to_s
261
- index = self.class::ITEM_TYPE_STRS.index(value_type_str).to_s(16).rjust(2, "0")
262
- index + value.encode
301
+ if self.class.const_defined? "ITEMS"
302
+ index.to_s(16).rjust(2, "0") + value.encode
263
303
  else
264
304
  self.class::VALUES.index(value).to_s(16).rjust(2, "0")
265
305
  end
266
306
  end
267
307
 
268
308
  def to_human
269
- if self.class.const_defined? "ITEM_TYPE_STRS"
309
+ if self.class.const_defined? "ITEMS"
310
+ @value.to_human
311
+ elsif self.class.const_defined? "INNER_TYPES"
270
312
  @value.to_human
271
313
  else
272
314
  @value
@@ -275,22 +317,23 @@ module Scale
275
317
  end
276
318
 
277
319
  module Vec
278
- include SingleValue # value is an array
320
+ include Base # value is an array
279
321
 
280
322
  module ClassMethods
281
323
  def decode(scale_bytes, raw = false)
324
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
282
325
  number = Scale::Types::Compact.decode(scale_bytes).value
283
326
  items = []
284
327
  number.times do
285
- type = Scale::Types.get(self::INNER_TYPE_STR)
286
- item = type.decode(scale_bytes)
328
+ item = self::INNER_TYPE.decode(scale_bytes)
287
329
  items << item
288
330
  end
331
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
289
332
  raw ? items : new(items)
290
333
  end
291
334
 
292
- def inner_type(type_str)
293
- const_set(:INNER_TYPE_STR, type_str)
335
+ def inner_type(type)
336
+ const_set(:INNER_TYPE, type)
294
337
  end
295
338
  end
296
339
 
@@ -309,14 +352,16 @@ module Scale
309
352
  end
310
353
 
311
354
  module Set
312
- include SingleValue
355
+ include Base
313
356
 
314
357
  module ClassMethods
315
358
  def decode(scale_bytes)
359
+ puts " BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
316
360
  value = "Scale::Types::U#{self::BYTE_LENGTH * 8}".constantize2.decode(scale_bytes).value
317
361
  return new [] unless value || value <= 0
318
362
 
319
363
  result = self::ITEMS.select { |_, mask| value & mask > 0 }.keys
364
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
320
365
  new result
321
366
  end
322
367
 
@@ -345,18 +390,21 @@ module Scale
345
390
  end
346
391
 
347
392
  module VecU8FixedLength
348
- include SingleValue
393
+ include Base
349
394
 
350
395
  module ClassMethods
351
396
  def decode(scale_bytes)
397
+ puts " BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
352
398
  byte_length = self::BYTE_LENGTH
353
399
  raise "#{self.name} byte length is wrong: #{byte_length}" unless %w[2 3 4 8 16 20 32 64 128 256].include?(byte_length.to_s)
354
400
 
355
401
  bytes = scale_bytes.get_next_bytes(byte_length)
356
402
  str = bytes.pack("C*").force_encoding("utf-8")
357
403
  if str.valid_encoding?
404
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
358
405
  new str
359
406
  else
407
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
360
408
  new bytes.bytes_to_hex
361
409
  end
362
410
  end
@@ -379,5 +427,39 @@ module Scale
379
427
  end
380
428
  end
381
429
 
430
+ module Array
431
+ include Base
432
+
433
+ module ClassMethods
434
+ def decode(scale_bytes)
435
+ puts "BEGIN " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
436
+ items = (0 ... self::LENGTH).map do |_|
437
+ self::INNER_TYPE.decode(scale_bytes)
438
+ end
439
+ puts " END " + self::TYPE_NAME + ": #{scale_bytes}" if Scale::Types.debug == true
440
+ new(items)
441
+ end
442
+
443
+ def inner_type(type)
444
+ const_set(:INNER_TYPE, type)
445
+ end
446
+
447
+ def length(len)
448
+ const_set(:LENGTH, len)
449
+ end
450
+ end
451
+
452
+ def self.included(base)
453
+ base.extend ClassMethods
454
+ end
455
+
456
+ def encode
457
+ self.value.map do |item|
458
+ item.encode
459
+ end.join
460
+ end
461
+ end
462
+
463
+
382
464
  end
383
465
  end