ic_agent 0.1.1
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 +7 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Dockerfile +17 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +108 -0
- data/LICENSE.txt +21 -0
- data/README.md +217 -0
- data/Rakefile +4 -0
- data/ic_agent.gemspec +53 -0
- data/lib/ic_agent/agent.rb +176 -0
- data/lib/ic_agent/ast/assembler.rb +192 -0
- data/lib/ic_agent/ast/did_grammar.treetop +159 -0
- data/lib/ic_agent/ast/did_grammar_v1.treetop +111 -0
- data/lib/ic_agent/ast/nodes/named_nodes.rb +410 -0
- data/lib/ic_agent/ast/nodes/string_literal.rb +17 -0
- data/lib/ic_agent/ast/parser.rb +85 -0
- data/lib/ic_agent/ast/writer.rb +19 -0
- data/lib/ic_agent/candid.rb +1671 -0
- data/lib/ic_agent/canister.rb +270 -0
- data/lib/ic_agent/certificate.rb +55 -0
- data/lib/ic_agent/client.rb +47 -0
- data/lib/ic_agent/common/cycles_wallet.rb +275 -0
- data/lib/ic_agent/common/governance.rb +366 -0
- data/lib/ic_agent/common/ledger.rb +177 -0
- data/lib/ic_agent/common/management.rb +69 -0
- data/lib/ic_agent/identity.rb +125 -0
- data/lib/ic_agent/principal.rb +112 -0
- data/lib/ic_agent/system_state.rb +43 -0
- data/lib/ic_agent/utils.rb +71 -0
- data/lib/ic_agent/version.rb +5 -0
- data/lib/ic_agent.rb +37 -0
- data/sig/ic_agent.rbs +4 -0
- metadata +288 -0
|
@@ -0,0 +1,1671 @@
|
|
|
1
|
+
require 'leb128'
|
|
2
|
+
require 'ctf_party'
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require 'digest'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require 'ruby_enum'
|
|
7
|
+
|
|
8
|
+
module IcAgent
|
|
9
|
+
class Candid
|
|
10
|
+
class TypeIds
|
|
11
|
+
include Ruby::Enum
|
|
12
|
+
include IcAgent::Utils
|
|
13
|
+
|
|
14
|
+
define :Null, -1
|
|
15
|
+
define :Bool, -2
|
|
16
|
+
define :Nat, -3
|
|
17
|
+
define :Int, -4
|
|
18
|
+
define :Nat8, -5
|
|
19
|
+
define :Nat16, -6
|
|
20
|
+
define :Nat32, -7
|
|
21
|
+
define :Nat64, -8
|
|
22
|
+
define :Int8, -9
|
|
23
|
+
define :Int16, -10
|
|
24
|
+
define :Int32, -11
|
|
25
|
+
define :Int64, -12
|
|
26
|
+
define :Float32, -13
|
|
27
|
+
define :Float64, -14
|
|
28
|
+
define :Text, -15
|
|
29
|
+
define :Reserved, -16
|
|
30
|
+
define :Empty, -17
|
|
31
|
+
define :Opt, -18
|
|
32
|
+
define :Vec, -19
|
|
33
|
+
define :Record, -20
|
|
34
|
+
define :Variant, -21
|
|
35
|
+
define :Func, -22
|
|
36
|
+
define :Service, -23
|
|
37
|
+
define :Principal, -24
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
PREFIX = 'DIDL'
|
|
41
|
+
SINGLE_TYPES = %w[null bool nat int nat8 nat16 nat32 nat64 int8 int16 int32 int64 float32 float64 text reserved empty principal]
|
|
42
|
+
MULTI_TYPES = %w[opt vec record variant func service blob]
|
|
43
|
+
RESULT_TYPE = %w[Ok Err]
|
|
44
|
+
|
|
45
|
+
ALL_TYPES = SINGLE_TYPES + MULTI_TYPES
|
|
46
|
+
|
|
47
|
+
class TypeTable
|
|
48
|
+
attr_accessor :typs, :idx
|
|
49
|
+
|
|
50
|
+
def initialize
|
|
51
|
+
@typs = []
|
|
52
|
+
@idx = {}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def has(obj)
|
|
56
|
+
return @idx.has_key?(obj.name)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def add(obj, buf)
|
|
60
|
+
idx = @typs.length
|
|
61
|
+
@idx[obj.name] = idx
|
|
62
|
+
@typs.append(buf)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def merge(obj, knot)
|
|
66
|
+
idx = self.has(obj) ? @idx[obj.name] : nil
|
|
67
|
+
knot_idx = @idx.has_key?(knot) ? @idx[knot] : nil
|
|
68
|
+
|
|
69
|
+
raise ValueError, "Missing type index for #{obj.name}" if idx == nil
|
|
70
|
+
raise ValueError, "Missing type index for #{knot}" if knot_idx == nil
|
|
71
|
+
|
|
72
|
+
@typs[idx] = @typs[knot_idx]
|
|
73
|
+
# delete the type
|
|
74
|
+
@typs.delete_at(knot_idx)
|
|
75
|
+
@idx.delete(knot)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def encode
|
|
79
|
+
l = 0
|
|
80
|
+
@typs.each do |t|
|
|
81
|
+
if t.length != 0
|
|
82
|
+
l += 1
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
length = LEB128.encode_signed(l).string
|
|
87
|
+
buf = @typs.join('')
|
|
88
|
+
return "#{length}#{buf}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def index_of(type_name)
|
|
92
|
+
raise ValueError, "Missing type index for #{type_name}" if !@idx.has_key?(type_name)
|
|
93
|
+
|
|
94
|
+
return LEB128.encode_signed(@idx[type_name] | 0).string
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Represents an IDL type.
|
|
99
|
+
class BaseType
|
|
100
|
+
def display
|
|
101
|
+
return self.name
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def build_type_table(type_table)
|
|
105
|
+
unless type_table.has(self)
|
|
106
|
+
self._build_type_table_impl(type_table)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def self.covariant
|
|
111
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.decode_value
|
|
115
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.encode_type
|
|
119
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def self.encode_value
|
|
123
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.check_type
|
|
127
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self._build_type_table_impl(type_table = nil)
|
|
131
|
+
raise NotImplementedError, 'subclass must implement abstract method'
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class PrimitiveType < BaseType
|
|
136
|
+
def initialize
|
|
137
|
+
super
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def check_type(t)
|
|
141
|
+
if self.name != t.name
|
|
142
|
+
raise ValueError, "type mismatch: type on the wire #{t.name}, expect type #{self.name}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
t
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def _build_type_table_impl(type_table = nil)
|
|
149
|
+
# No type table encoding for Primitive types.
|
|
150
|
+
return
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class ConstructType < BaseType
|
|
155
|
+
def initialize
|
|
156
|
+
super
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def check_type(t)
|
|
160
|
+
if t.is_a?(RecClass)
|
|
161
|
+
ty = t.get_type()
|
|
162
|
+
if ty == nil
|
|
163
|
+
raise ValueError, 'type mismatch with uninitialized type'
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
return ty
|
|
167
|
+
else
|
|
168
|
+
raise ValueError, "type mismatch: type on the wire #{t.name}, expect type #{self.name}"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def encode_type(type_table)
|
|
173
|
+
return type_table.index_of(self.name)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class NullClass < PrimitiveType
|
|
178
|
+
def initialize()
|
|
179
|
+
super
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def covariant(x)
|
|
183
|
+
x == nil
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def encode_value(val)
|
|
187
|
+
''
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def encode_type(type_table = nil)
|
|
191
|
+
LEB128.encode_signed(TypeIds::Null).string
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def decode_value(b, t)
|
|
195
|
+
check_type(t)
|
|
196
|
+
return nil
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def name
|
|
200
|
+
'null'
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def id
|
|
204
|
+
TypeIds::Null
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
class EmptyClass < PrimitiveType
|
|
209
|
+
def initialize
|
|
210
|
+
super
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def covariant(x)
|
|
214
|
+
false
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def encode_value(val)
|
|
218
|
+
raise ValueError, 'Empty cannot appear as a function argument'
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def encode_type(type_table = nil)
|
|
222
|
+
LEB128.encode_signed(TypeIds::Empty).string
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def decode_value(b, t)
|
|
226
|
+
raise ValueError, 'Empty cannot appear as an output'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def name
|
|
230
|
+
'empty'
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def id
|
|
234
|
+
TypeIds::Empty
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
class BoolClass < PrimitiveType
|
|
239
|
+
def initialize
|
|
240
|
+
super
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def covariant(x)
|
|
244
|
+
x.is_a?(TrueClass) || x.is_a?(FalseClass)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def encode_value(val)
|
|
248
|
+
LEB128.encode_signed(val ? 1 : 0).string
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def encode_type(type_table = nil)
|
|
252
|
+
LEB128.encode_signed(TypeIds::Bool).string
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def decode_value(b, t)
|
|
256
|
+
check_type(t)
|
|
257
|
+
byte = IcAgent::Candid.safe_read_byte(b)
|
|
258
|
+
str_io = StringIO.new
|
|
259
|
+
str_io.putc(byte.hex)
|
|
260
|
+
if LEB128.decode_signed(str_io) == 1
|
|
261
|
+
true
|
|
262
|
+
elsif LEB128.decode_signed(str_io) == 0
|
|
263
|
+
false
|
|
264
|
+
else
|
|
265
|
+
raise ValueError, 'Boolean value out of range'
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def name
|
|
270
|
+
'bool'
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def id
|
|
274
|
+
TypeIds::Bool
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
class ReservedClass < PrimitiveType
|
|
279
|
+
def initialize
|
|
280
|
+
super
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def covariant(x)
|
|
284
|
+
true
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def encode_value
|
|
288
|
+
''
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def encode_type(type_table = nil)
|
|
292
|
+
LEB128.encode_signed(TypeIds::Reserved).string
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def decode_value(b, t)
|
|
296
|
+
if name != t.name
|
|
297
|
+
t.decode_value(b, t)
|
|
298
|
+
end
|
|
299
|
+
nil
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def name
|
|
303
|
+
'reserved'
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def id
|
|
307
|
+
TypeIds::Reserved
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
class TextClass < PrimitiveType
|
|
312
|
+
def initialize
|
|
313
|
+
super
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def covariant(x)
|
|
317
|
+
x.is_a?(String)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def encode_value(val)
|
|
321
|
+
buf = val.encode(Encoding::UTF_8)
|
|
322
|
+
length = LEB128.encode_signed(buf.length).string
|
|
323
|
+
length + buf
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def encode_type(type_table = nil)
|
|
327
|
+
LEB128.encode_signed(TypeIds::Text).string
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def decode_value(b, t)
|
|
331
|
+
check_type(t)
|
|
332
|
+
length = IcAgent::Candid.leb128u_decode(b).to_i
|
|
333
|
+
buf = IcAgent::Candid.safe_read(b, length)
|
|
334
|
+
buf.hex2str
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def name
|
|
338
|
+
'text'
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def id
|
|
342
|
+
TypeIds::Text
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
class IntClass < PrimitiveType
|
|
347
|
+
def initialize
|
|
348
|
+
super
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def covariant(x)
|
|
352
|
+
x.is_a?(Integer)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def encode_value(val)
|
|
356
|
+
LEB128.encode_signed(val).string
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def encode_type(type_table = nil)
|
|
360
|
+
LEB128.encode_signed(TypeIds::Int).string
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def decode_value(b, t)
|
|
364
|
+
check_type(t)
|
|
365
|
+
IcAgent::Candid.leb128i_decode(b)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def name
|
|
369
|
+
'int'
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def id
|
|
373
|
+
TypeIds::Int
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
class NatClass < PrimitiveType
|
|
378
|
+
def initialize
|
|
379
|
+
super
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def covariant(x)
|
|
383
|
+
x.is_a?(Integer) && x >= 0
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def encode_value(val)
|
|
387
|
+
LEB128.encode_signed(val).string
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def encode_type(type_table = nil)
|
|
391
|
+
LEB128.encode_signed(TypeIds::Nat).string
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def decode_value(pipe, t)
|
|
395
|
+
check_type(t)
|
|
396
|
+
IcAgent::Candid.leb128u_decode(pipe)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def name
|
|
400
|
+
'nat'
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def id
|
|
404
|
+
TypeIds::Nat
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
class FloatClass < PrimitiveType
|
|
409
|
+
def initialize(bits)
|
|
410
|
+
super()
|
|
411
|
+
@bits = bits
|
|
412
|
+
raise ArgumentError, 'not a valid float type' unless [32, 64].include?(@bits)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def covariant(x)
|
|
416
|
+
x.is_a?(Float)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def encode_value(val)
|
|
420
|
+
if @bits == 32
|
|
421
|
+
[val].pack('f')
|
|
422
|
+
elsif @bits == 64
|
|
423
|
+
[val].pack('d')
|
|
424
|
+
else
|
|
425
|
+
raise ValueError, 'The length of float have to be 32 bits or 64 bits '
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def encode_type(type_table = nil)
|
|
430
|
+
opcode = if @bits == 32
|
|
431
|
+
TypeIds::Float32
|
|
432
|
+
else
|
|
433
|
+
TypeIds::Float64
|
|
434
|
+
end
|
|
435
|
+
LEB128.encode_signed(opcode).string
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def decode_value(b, t)
|
|
439
|
+
check_type(t)
|
|
440
|
+
by = IcAgent::Candid.safe_read(b, @bits / 8)
|
|
441
|
+
if @bits == 32
|
|
442
|
+
by.hex2str.unpack('f')[0]
|
|
443
|
+
elsif @bits == 64
|
|
444
|
+
by.hex2str.unpack('d')[0]
|
|
445
|
+
else
|
|
446
|
+
raise ValueError, 'The length of float have to be 32 bits or 64 bits '
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def name
|
|
451
|
+
"float#{@bits}"
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def id
|
|
455
|
+
if @bits == 32
|
|
456
|
+
TypeIds::Float32
|
|
457
|
+
else
|
|
458
|
+
TypeIds::Float64
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
class FixedIntClass < PrimitiveType
|
|
464
|
+
def initialize(bits)
|
|
465
|
+
super()
|
|
466
|
+
@bits = bits
|
|
467
|
+
unless [8, 16, 32, 64].include?(@bits)
|
|
468
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
def covariant(x)
|
|
473
|
+
min_val = -1 * 2**(@bits - 1)
|
|
474
|
+
max_val = -1 + 2**(@bits - 1)
|
|
475
|
+
if x >= min_val && x <= max_val
|
|
476
|
+
true
|
|
477
|
+
else
|
|
478
|
+
false
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def encode_value(val)
|
|
483
|
+
case @bits
|
|
484
|
+
when 8
|
|
485
|
+
buf = [val].pack('c') # signed char -> Int8
|
|
486
|
+
when 16
|
|
487
|
+
buf = [val].pack('s') # short -> Int16
|
|
488
|
+
when 32
|
|
489
|
+
buf = [val].pack('l') # int -> Int32
|
|
490
|
+
when 64
|
|
491
|
+
buf = [val].pack('q') # long long -> Int64
|
|
492
|
+
else
|
|
493
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
494
|
+
end
|
|
495
|
+
buf
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def encode_type(type_table = nil)
|
|
499
|
+
offset = (Math.log2(@bits) - 3).to_i
|
|
500
|
+
LEB128.encode_signed(-9 - offset).string
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def decode_value(b, t)
|
|
504
|
+
check_type(t)
|
|
505
|
+
by = IcAgent::Candid.safe_read(b, @bits / 8)
|
|
506
|
+
case @bits
|
|
507
|
+
when 8
|
|
508
|
+
by.hex2str.unpack('c')[0] # signed char -> Int8
|
|
509
|
+
when 16
|
|
510
|
+
by.hex2str.unpack('s')[0] # short -> Int16
|
|
511
|
+
when 32
|
|
512
|
+
by.hex2str.unpack('l')[0] # int -> Int32
|
|
513
|
+
when 64
|
|
514
|
+
by.hex2str.unpack('q')[0] # long long -> Int64
|
|
515
|
+
else
|
|
516
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def name
|
|
521
|
+
"int#{@bits.to_s}"
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def id
|
|
525
|
+
case @bits
|
|
526
|
+
when 8
|
|
527
|
+
TypeIds::Int8
|
|
528
|
+
when 16
|
|
529
|
+
TypeIds::Int16
|
|
530
|
+
when 32
|
|
531
|
+
TypeIds::Int32
|
|
532
|
+
when 64
|
|
533
|
+
TypeIds::Int64
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
class FixedNatClass < PrimitiveType
|
|
539
|
+
def initialize(bits)
|
|
540
|
+
super()
|
|
541
|
+
@bits = bits
|
|
542
|
+
unless [8, 16, 32, 64].include? bits
|
|
543
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def covariant(x)
|
|
548
|
+
max_val = -1 + 2**@bits
|
|
549
|
+
x >= 0 && x <= max_val
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def encode_value(val)
|
|
553
|
+
case @bits
|
|
554
|
+
when 8
|
|
555
|
+
buf = [val].pack('C') # unsigned char -> Nat8
|
|
556
|
+
when 16
|
|
557
|
+
buf = [val].pack('S') # unsigned short -> Nat16
|
|
558
|
+
when 32
|
|
559
|
+
buf = [val].pack('L') # unsigned int -> Nat32
|
|
560
|
+
when 64
|
|
561
|
+
buf = [val].pack('Q') # unsigned long long -> Nat64
|
|
562
|
+
else
|
|
563
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
564
|
+
end
|
|
565
|
+
buf
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def encode_type(type_table = nil)
|
|
569
|
+
offset = Math.log2(@bits).to_i - 3
|
|
570
|
+
LEB128.encode_signed(-5 - offset).string
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def decode_value(b, t)
|
|
574
|
+
check_type(t)
|
|
575
|
+
by = IcAgent::Candid.safe_read(b, @bits / 8)
|
|
576
|
+
case @bits
|
|
577
|
+
when 8
|
|
578
|
+
return by.hex2str.unpack('C').first # unsigned char -> Nat8
|
|
579
|
+
when 16
|
|
580
|
+
return by.hex2str.unpack('S').first # unsigned short -> Nat16
|
|
581
|
+
when 32
|
|
582
|
+
return by.hex2str.unpack('L').first # unsigned int -> Nat32
|
|
583
|
+
when 64
|
|
584
|
+
return by.hex2str.unpack('Q').first # unsigned long long -> Nat64
|
|
585
|
+
else
|
|
586
|
+
raise ArgumentError, 'bits only support 8, 16, 32, 64'
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def name
|
|
591
|
+
"nat#{@bits}"
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
def id
|
|
595
|
+
case @bits
|
|
596
|
+
when 8
|
|
597
|
+
TypeIds::Nat8
|
|
598
|
+
when 16
|
|
599
|
+
TypeIds::Nat16
|
|
600
|
+
when 32
|
|
601
|
+
TypeIds::Nat32
|
|
602
|
+
when 64
|
|
603
|
+
TypeIds::Nat64
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
class PrincipalClass < PrimitiveType
|
|
609
|
+
def initialize
|
|
610
|
+
super
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def covariant(x)
|
|
614
|
+
if x.is_a?(String)
|
|
615
|
+
p = IcAgent::Principal.from_str(x)
|
|
616
|
+
elsif x.is_a?(Array)
|
|
617
|
+
p = IcAgent::Principal.from_hex(x.pack('C*').unpack1('H*'))
|
|
618
|
+
else
|
|
619
|
+
raise ValueError, 'only support string or bytes format'
|
|
620
|
+
end
|
|
621
|
+
p.is_a?(IcAgent::Principal)
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
def encode_value(val)
|
|
625
|
+
tag = 1.chr(Encoding::ASCII_8BIT)
|
|
626
|
+
if val.is_a?(String)
|
|
627
|
+
buf = IcAgent::Principal.from_str(val).bytes
|
|
628
|
+
elsif val.is_a?(Array)
|
|
629
|
+
buf = val.pack('C*')
|
|
630
|
+
else
|
|
631
|
+
raise ValueError, 'Principal should be string or bytes.'
|
|
632
|
+
end
|
|
633
|
+
l = LEB128.encode_signed(buf.size).string
|
|
634
|
+
tag + l + buf
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
def encode_type(type_table = nil)
|
|
638
|
+
LEB128.encode_signed(TypeIds::Principal).string
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
def decode_value(b, t)
|
|
642
|
+
check_type(t)
|
|
643
|
+
res = IcAgent::Candid.safe_read_byte(b)
|
|
644
|
+
if res != '01'
|
|
645
|
+
raise ValueError, 'Cannot decode principal'
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
length = IcAgent::Candid.leb128u_decode(b)
|
|
649
|
+
IcAgent::Principal.from_hex(IcAgent::Candid.safe_read(b, length)).to_str
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def name
|
|
653
|
+
'principal'
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def id
|
|
657
|
+
TypeIds::Principal
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
class VecClass < ConstructType
|
|
662
|
+
def initialize(_type)
|
|
663
|
+
super()
|
|
664
|
+
@interior_type = _type
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def covariant(x)
|
|
668
|
+
x.is_a?(Enumerable) && !x.any? { |item| !@interior_type.covariant(item) }
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def encode_value(val)
|
|
672
|
+
length = LEB128.encode_signed(val.length).string
|
|
673
|
+
vec = val.map { |v| @interior_type.encode_value(v) }
|
|
674
|
+
(length + vec.join).b
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
def _build_type_table_impl(type_table)
|
|
678
|
+
@interior_type.build_type_table(type_table)
|
|
679
|
+
op_code = LEB128.encode_signed(TypeIds::Vec).string
|
|
680
|
+
buffer = @interior_type.encode_type(type_table)
|
|
681
|
+
type_table.add(self, op_code + buffer)
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def decode_value(b, t)
|
|
685
|
+
vec = check_type(t)
|
|
686
|
+
raise 'Not a vector type' unless vec.is_a?(VecClass)
|
|
687
|
+
|
|
688
|
+
length = IcAgent::Candid.leb128u_decode(b)
|
|
689
|
+
rets = []
|
|
690
|
+
length.times { rets << @interior_type.decode_value(b, @interior_type) }
|
|
691
|
+
rets
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
def name
|
|
695
|
+
"vec (#{@interior_type.name})"
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def id
|
|
699
|
+
TypeIds::Vec
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def display
|
|
703
|
+
"vec #{@interior_type.display}"
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
class OptClass < ConstructType
|
|
708
|
+
def initialize(_type)
|
|
709
|
+
super()
|
|
710
|
+
@type = _type
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
def covariant(x)
|
|
714
|
+
x.is_a?(Array) && (x.empty? || (x.length == 1 && @type.covariant(x[0])))
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def encode_value(val)
|
|
718
|
+
if val.empty?
|
|
719
|
+
"\x00".b
|
|
720
|
+
else
|
|
721
|
+
"\x01".b + @type.encode_value(val[0])
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
def _build_type_table_impl(type_table)
|
|
726
|
+
@type.build_type_table(type_table)
|
|
727
|
+
op_code = LEB128.encode_signed(TypeIds::Opt).string
|
|
728
|
+
buffer = @type.encode_type(type_table)
|
|
729
|
+
type_table.add(self, op_code + buffer)
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def decode_value(b, t)
|
|
733
|
+
opt = check_type(t)
|
|
734
|
+
raise ValueError, 'Not an option type' unless opt.is_a?(OptClass)
|
|
735
|
+
|
|
736
|
+
flag = IcAgent::Candid.safe_read_byte(b)
|
|
737
|
+
if flag == '00'
|
|
738
|
+
[]
|
|
739
|
+
elsif flag == '01'
|
|
740
|
+
[@type.decode_value(b, opt.instance_variable_get(:@type))]
|
|
741
|
+
else
|
|
742
|
+
raise ValueError, 'Not an option value'
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def name
|
|
747
|
+
"opt (#{@type.name})"
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
def id
|
|
751
|
+
TypeIds::Opt
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
def display
|
|
755
|
+
"opt (#{@type.display})"
|
|
756
|
+
end
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
class RecordClass < ConstructType
|
|
760
|
+
def initialize(field)
|
|
761
|
+
super()
|
|
762
|
+
@fields = field.sort_by { |k, _v| IcAgent::Utils.label_hash(k) }.to_h
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
def try_as_tuple
|
|
766
|
+
res = []
|
|
767
|
+
idx = 0
|
|
768
|
+
@fields.each do |k, v|
|
|
769
|
+
return nil unless k == "_#{idx}_" # check
|
|
770
|
+
|
|
771
|
+
res << v
|
|
772
|
+
idx += 1
|
|
773
|
+
end
|
|
774
|
+
res
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
def covariant(x)
|
|
778
|
+
raise ArgumentError, 'Expected dict type input.' unless x.is_a?(Hash)
|
|
779
|
+
|
|
780
|
+
@fields.each do |k, v|
|
|
781
|
+
raise ArgumentError, "Record is missing key #{k}" unless x.key?(k)
|
|
782
|
+
return false unless v.covariant(x[k])
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
true
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
def encode_value(val)
|
|
789
|
+
bufs = @fields.map { |k, v| v.encode_value(val[k]) }
|
|
790
|
+
bufs.join.b
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
def _build_type_table_impl(type_table)
|
|
794
|
+
@fields.values.each do |field_value|
|
|
795
|
+
field_value.send(:build_type_table, type_table)
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
op_code = LEB128.encode_signed(TypeIds::Record).string
|
|
799
|
+
length = LEB128.encode_signed(@fields.size).string
|
|
800
|
+
|
|
801
|
+
fields = @fields.map { |k, v|
|
|
802
|
+
LEB128.encode_signed(IcAgent::Utils.label_hash(k)).string + v.encode_type(type_table)
|
|
803
|
+
}.join.b
|
|
804
|
+
type_table.add(self, op_code + length + fields)
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
def decode_value(b, t)
|
|
808
|
+
record = check_type(t)
|
|
809
|
+
raise ArgumentError, 'Not a record type' unless record.is_a?(RecordClass)
|
|
810
|
+
|
|
811
|
+
x = {}
|
|
812
|
+
idx = 0
|
|
813
|
+
keys = @fields.keys
|
|
814
|
+
@fields.each do |k, v|
|
|
815
|
+
if idx >= @fields.length || IcAgent::Utils.label_hash(keys[idx]) != IcAgent::Utils.label_hash(k)
|
|
816
|
+
# skip field
|
|
817
|
+
v.decode_value(b, v)
|
|
818
|
+
next
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
expect_key = keys[idx]
|
|
822
|
+
expected_value = @fields[expect_key]
|
|
823
|
+
x[expect_key] = expected_value.decode_value(b, v)
|
|
824
|
+
idx += 1
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
raise ArgumentError, "Cannot find field #{keys[idx]}" if idx < @fields.length
|
|
828
|
+
|
|
829
|
+
x
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
def name
|
|
833
|
+
fields = @fields.map { |k, v| "#{k}:#{v.name}" }.join(';')
|
|
834
|
+
"record {#{fields}}"
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
def id
|
|
838
|
+
TypeIds::Record
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
def display
|
|
842
|
+
d = {}
|
|
843
|
+
@fields.each { |k, v| d[v] = v.display }
|
|
844
|
+
"record #{d}"
|
|
845
|
+
end
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
class TupleClass < RecordClass
|
|
849
|
+
attr_accessor :components
|
|
850
|
+
|
|
851
|
+
def initialize(*_components)
|
|
852
|
+
x = {}
|
|
853
|
+
_components.each_with_index do |v, i|
|
|
854
|
+
x["_#{i}_"] = v
|
|
855
|
+
end
|
|
856
|
+
super(x)
|
|
857
|
+
@components = _components
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
def covariant(x)
|
|
861
|
+
unless x.is_a?(Array)
|
|
862
|
+
raise ValueError, 'Expected tuple type input.'
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
@components.each_with_index do |v, idx|
|
|
866
|
+
unless v.covariant(x[idx])
|
|
867
|
+
return false
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
x.length >= @fields.length
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
def encode_value(val)
|
|
874
|
+
bufs = ''.b
|
|
875
|
+
@components.each_with_index do |_, i|
|
|
876
|
+
bufs += @components[i].encode_value(val[i])
|
|
877
|
+
end
|
|
878
|
+
bufs
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
def decode_value(b, t)
|
|
882
|
+
tup = check_type(t)
|
|
883
|
+
unless tup.is_a?(TupleClass)
|
|
884
|
+
raise ValueError, 'not a tuple type'
|
|
885
|
+
end
|
|
886
|
+
unless tup.components.length == @components.length
|
|
887
|
+
raise ValueError, 'tuple mismatch'
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
res = []
|
|
891
|
+
tup.components.each_with_index do |wireType, i|
|
|
892
|
+
if i >= @components.length
|
|
893
|
+
wireType.decode_value(b, wireType)
|
|
894
|
+
else
|
|
895
|
+
res << @components[i].decode_value(b, wireType)
|
|
896
|
+
end
|
|
897
|
+
end
|
|
898
|
+
res
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
def id
|
|
902
|
+
TypeIds::Tuple
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
def display
|
|
906
|
+
d = @components.map { |item| item.display() }
|
|
907
|
+
"record {#{d.join(';')}}"
|
|
908
|
+
end
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
class VariantClass < ConstructType
|
|
912
|
+
attr_accessor :fields
|
|
913
|
+
|
|
914
|
+
def initialize(field)
|
|
915
|
+
super()
|
|
916
|
+
@fields = field.sort_by { |kv| IcAgent::Utils.label_hash(kv[0]) }.to_h
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
def covariant(x)
|
|
920
|
+
return false unless x.length == 1
|
|
921
|
+
|
|
922
|
+
@fields.each do |k, v|
|
|
923
|
+
next if !x.key?(k) || v.covariant(x[k])
|
|
924
|
+
|
|
925
|
+
return false
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
true
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
def encode_value(val)
|
|
932
|
+
idx = 0
|
|
933
|
+
@fields.each do |name, ty|
|
|
934
|
+
if val.key?(name)
|
|
935
|
+
count = LEB128.encode_signed(idx).string
|
|
936
|
+
buf = ty.encode_value(val[name])
|
|
937
|
+
return count + buf
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
idx += 1
|
|
941
|
+
end
|
|
942
|
+
raise "Variant has no data: #{val}"
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
def _build_type_table_impl(type_table)
|
|
946
|
+
@fields.each do |_, v|
|
|
947
|
+
v.build_type_table(type_table)
|
|
948
|
+
end
|
|
949
|
+
opCode = LEB128.encode_signed(TypeIds::Variant).string
|
|
950
|
+
length = LEB128.encode_signed(@fields.length).string
|
|
951
|
+
fields = ''.b
|
|
952
|
+
@fields.each do |k, v|
|
|
953
|
+
fields += LEB128.encode_signed(IcAgent::Utils.label_hash(k)).string + v.encode_type(type_table)
|
|
954
|
+
end
|
|
955
|
+
type_table.add(self, opCode + length + fields)
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
def decode_value(b, t)
|
|
959
|
+
variant = check_type(t)
|
|
960
|
+
raise 'Not a variant type' unless variant.is_a?(VariantClass)
|
|
961
|
+
|
|
962
|
+
idx = IcAgent::Candid.leb128u_decode(b)
|
|
963
|
+
raise "Invalid variant index: #{idx}" if idx >= variant.fields.length
|
|
964
|
+
|
|
965
|
+
keys = variant.fields.keys
|
|
966
|
+
wireHash = keys[idx]
|
|
967
|
+
wireType = variant.fields[wireHash]
|
|
968
|
+
|
|
969
|
+
@fields.each do |key, expectType|
|
|
970
|
+
next unless IcAgent::Utils.label_hash(wireHash) == IcAgent::Utils.label_hash(key)
|
|
971
|
+
|
|
972
|
+
ret = {}
|
|
973
|
+
value = expectType ? expectType.decode_value(b, wireType) : nil
|
|
974
|
+
ret[key] = value
|
|
975
|
+
return ret
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
raise "Cannot find field hash #{wireHash}"
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def name
|
|
982
|
+
fields = @fields.map { |k, v| "#{k}:#{v.name || ''}" }.join(';')
|
|
983
|
+
"variant {#{fields}}"
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
def id
|
|
987
|
+
TypeIds::Variant
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
def display
|
|
991
|
+
d = {}
|
|
992
|
+
@fields.each do |k, v|
|
|
993
|
+
d[k] = v.name || ''
|
|
994
|
+
end
|
|
995
|
+
"variant #{d}"
|
|
996
|
+
end
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
class RecClass < ConstructType
|
|
1000
|
+
@@counter = 0
|
|
1001
|
+
|
|
1002
|
+
def initialize
|
|
1003
|
+
super()
|
|
1004
|
+
@id = @@counter
|
|
1005
|
+
@@counter += 1
|
|
1006
|
+
@type = nil
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
def fill(t)
|
|
1010
|
+
@type = t
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
def get_type
|
|
1014
|
+
if @type.is_a?(RecClass)
|
|
1015
|
+
@type.get_type
|
|
1016
|
+
else
|
|
1017
|
+
@type
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
def covariant(x)
|
|
1022
|
+
return false if @type.nil?
|
|
1023
|
+
|
|
1024
|
+
@type.covariant(x)
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
def encode_value(val)
|
|
1028
|
+
if @type.nil?
|
|
1029
|
+
raise 'Recursive type uninitialized'
|
|
1030
|
+
else
|
|
1031
|
+
@type.encode_value(val)
|
|
1032
|
+
end
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
def encode_type(type_table)
|
|
1036
|
+
if @type.is_a?(PrimitiveType)
|
|
1037
|
+
@type.encode_type(type_table)
|
|
1038
|
+
else
|
|
1039
|
+
super.encode_type(type_table)
|
|
1040
|
+
end
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
def _build_type_table_impl(type_table)
|
|
1044
|
+
if @type.nil?
|
|
1045
|
+
raise 'Recursive type uninitialized'
|
|
1046
|
+
else
|
|
1047
|
+
if !get_type.is_a?(PrimitiveType)
|
|
1048
|
+
type_table.add(self, '')
|
|
1049
|
+
@type.build_type_table(type_table)
|
|
1050
|
+
type_table.merge(self, @type.name)
|
|
1051
|
+
end
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
def decode_value(b, t)
|
|
1056
|
+
if @type.nil?
|
|
1057
|
+
raise 'Recursive type uninitialized'
|
|
1058
|
+
else
|
|
1059
|
+
@type.decode_value(b, t)
|
|
1060
|
+
end
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
def name
|
|
1064
|
+
"rec_#{@id}"
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
def display
|
|
1068
|
+
if @type.nil?
|
|
1069
|
+
raise 'Recursive type uninitialized'
|
|
1070
|
+
else
|
|
1071
|
+
"#{name}.#{@type.name}"
|
|
1072
|
+
end
|
|
1073
|
+
end
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1076
|
+
class FuncClass < ConstructType
|
|
1077
|
+
attr_accessor :arg_types, :ret_types, :annotations
|
|
1078
|
+
|
|
1079
|
+
def initialize(arg_types, ret_types, annotations)
|
|
1080
|
+
super()
|
|
1081
|
+
@arg_types = arg_types
|
|
1082
|
+
@ret_types = ret_types
|
|
1083
|
+
@annotations = annotations
|
|
1084
|
+
end
|
|
1085
|
+
|
|
1086
|
+
def covariant(x)
|
|
1087
|
+
x.is_a?(Array) && x.length == 2 && x[0] &&
|
|
1088
|
+
(x[0].is_a?(String) ? IcAgent::Principal.from_str(x[0]) : IcAgent::Principal.from_hex(x[0].unpack('H*').first)).is_a?(IcAgent::Principal) &&
|
|
1089
|
+
x[1].is_a?(String)
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
def encode_value(vals)
|
|
1093
|
+
principal = vals[0]
|
|
1094
|
+
method_name = vals[1]
|
|
1095
|
+
tag = [1].pack('C')
|
|
1096
|
+
if principal.is_a?(String)
|
|
1097
|
+
buf = IcAgent::Principal.from_str(principal).bytes
|
|
1098
|
+
elsif principal.is_a?(String)
|
|
1099
|
+
buf = principal
|
|
1100
|
+
else
|
|
1101
|
+
raise ArgumentError, 'Principal should be string or bytes.'
|
|
1102
|
+
end
|
|
1103
|
+
l = LEB128.encode_signed(buf.length).string
|
|
1104
|
+
canister = tag + l + buf
|
|
1105
|
+
|
|
1106
|
+
method = method_name.encode
|
|
1107
|
+
method_len = LEB128.encode_signed(method.length).string
|
|
1108
|
+
tag + canister + method_len + method
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
def _build_type_table_impl(type_table)
|
|
1112
|
+
@arg_types.each { |arg| arg.build_type_table(type_table) }
|
|
1113
|
+
@ret_types.each { |ret| ret.build_type_table(type_table) }
|
|
1114
|
+
|
|
1115
|
+
op_code = LEB128.encode_signed(TypeIds::Func).string
|
|
1116
|
+
arg_len = LEB128.encode_signed(@arg_types.length).string
|
|
1117
|
+
args = ''
|
|
1118
|
+
@arg_types.each { |arg| args += arg.encode_type(type_table) }
|
|
1119
|
+
ret_len = LEB128.encode_signed(@ret_types.length).string
|
|
1120
|
+
rets = ''
|
|
1121
|
+
@ret_types.each { |ret| rets += ret.encode_type(type_table) }
|
|
1122
|
+
ann_len = LEB128.encode_signed(@annotations.length).string
|
|
1123
|
+
anns = ''
|
|
1124
|
+
@annotations.each { |a| anns += _encode_annotation(a) }
|
|
1125
|
+
type_table.add(self, op_code + arg_len + args + ret_len + rets + ann_len + anns)
|
|
1126
|
+
end
|
|
1127
|
+
|
|
1128
|
+
def decode_value(b, t)
|
|
1129
|
+
x = IcAgent::Candid.safe_read_byte(b)
|
|
1130
|
+
raise ArgumentError, 'Cannot decode function reference' unless x == '01'
|
|
1131
|
+
|
|
1132
|
+
res = IcAgent::Candid.safe_read_byte(b)
|
|
1133
|
+
raise ArgumentError, 'Cannot decode principal' unless res == '01'
|
|
1134
|
+
|
|
1135
|
+
length = IcAgent::Candid.leb128u_decode(b)
|
|
1136
|
+
canister = IcAgent::Principal.from_hex(IcAgent::Candid.safe_read(b, length)).to_str
|
|
1137
|
+
mLen = IcAgent::Candid.leb128u_decode(b)
|
|
1138
|
+
buf = IcAgent::Candid.safe_read(b, mLen)
|
|
1139
|
+
method = buf.hex2str
|
|
1140
|
+
|
|
1141
|
+
[canister, method]
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def name
|
|
1145
|
+
args = @arg_types.map { |arg| arg.name }.join(', ')
|
|
1146
|
+
rets = @ret_types.map { |ret| ret.name }.join(', ')
|
|
1147
|
+
anns = @annotations.join(' ')
|
|
1148
|
+
"(#{args}) → (#{rets}) #{anns}"
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
def id
|
|
1152
|
+
TypeIds::Func
|
|
1153
|
+
end
|
|
1154
|
+
|
|
1155
|
+
def display
|
|
1156
|
+
args = @arg_types.map { |arg| arg.display }.join(', ')
|
|
1157
|
+
rets = @ret_types.map { |ret| ret.display }.join(', ')
|
|
1158
|
+
anns = @annotations.join(' ')
|
|
1159
|
+
"(#{args}) → (#{rets}) #{anns}"
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
def _encode_annotation(ann)
|
|
1163
|
+
if ann == 'query'
|
|
1164
|
+
return [1].pack('C')
|
|
1165
|
+
elsif ann == 'oneway'
|
|
1166
|
+
return [2].pack('C')
|
|
1167
|
+
else
|
|
1168
|
+
raise 'Illeagal function annotation'
|
|
1169
|
+
end
|
|
1170
|
+
end
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
class ServiceClass < ConstructType
|
|
1174
|
+
def initialize(field)
|
|
1175
|
+
super()
|
|
1176
|
+
@fields = Hash[field.sort_by { |k, _| IcAgent::Utils.label_hash(k.to_s) }]
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
def covariant(x)
|
|
1180
|
+
if x.is_a?(String)
|
|
1181
|
+
p = IcAgent::Principal.from_str(x)
|
|
1182
|
+
elsif x.is_a?(Array)
|
|
1183
|
+
p = IcAgent::Principal.from_hex(x.pack('C*').unpack1('H*'))
|
|
1184
|
+
else
|
|
1185
|
+
raise ArgumentError, 'only support string or bytes format'
|
|
1186
|
+
end
|
|
1187
|
+
p.is_a?(IcAgent::Principal)
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
def encode_value(val)
|
|
1191
|
+
tag = [1].pack('C')
|
|
1192
|
+
if val.is_a?(String)
|
|
1193
|
+
buf = IcAgent::Principal.from_str(val).bytes
|
|
1194
|
+
elsif val.is_a?(Array)
|
|
1195
|
+
buf = val
|
|
1196
|
+
else
|
|
1197
|
+
raise ArgumentError, 'Principal should be string or bytes.'
|
|
1198
|
+
end
|
|
1199
|
+
l = LEB128.encode_signed(buf.length).string
|
|
1200
|
+
tag + l + buf
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1203
|
+
def _build_type_table_impl(type_table)
|
|
1204
|
+
@fields.each_value { |v| v.build_type_table(type_table) }
|
|
1205
|
+
op_code = LEB128.encode_signed(TypeIds::Service).string
|
|
1206
|
+
length = LEB128.encode_signed(@fields.length).string
|
|
1207
|
+
fields = ''.b
|
|
1208
|
+
@fields.each { |k, v|
|
|
1209
|
+
fields += LEB128.encode_signed(k.to_s.bytesize).string + k.to_s + v.encode_type(type_table)
|
|
1210
|
+
}
|
|
1211
|
+
type_table.add(self, op_code + length + fields)
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
def decode_value(b, t)
|
|
1215
|
+
res = IcAgent::Candid.safe_read_byte(b)
|
|
1216
|
+
raise ArgumentError, 'Cannot decode principal' unless res == '01'
|
|
1217
|
+
|
|
1218
|
+
length = IcAgent::Candid.leb128u_decode(b)
|
|
1219
|
+
IcAgent::Principal.from_hex(IcAgent::Candid.safe_read(b, length)).to_str
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
def name
|
|
1223
|
+
fields = @fields.map { |k, v| "#{k} : #{v.name}" }.join(', ')
|
|
1224
|
+
"service #{fields}"
|
|
1225
|
+
end
|
|
1226
|
+
|
|
1227
|
+
def id
|
|
1228
|
+
TypeIds::Service
|
|
1229
|
+
end
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
#####################
|
|
1233
|
+
|
|
1234
|
+
class Pipe
|
|
1235
|
+
def initialize(buffer = '', length = 0)
|
|
1236
|
+
@buffer = buffer
|
|
1237
|
+
@view = buffer[0...buffer.size]
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
def buffer
|
|
1241
|
+
@view
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
def length
|
|
1245
|
+
@view.size
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
def end?
|
|
1249
|
+
length == 0
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
def read(num)
|
|
1253
|
+
if @view.size < num
|
|
1254
|
+
raise ValueError, 'Wrong: out of bound'
|
|
1255
|
+
end
|
|
1256
|
+
|
|
1257
|
+
read_num = num * 2
|
|
1258
|
+
res = @view[0...read_num]
|
|
1259
|
+
@view = @view[read_num...@view.length]
|
|
1260
|
+
return res
|
|
1261
|
+
end
|
|
1262
|
+
|
|
1263
|
+
def readbyte
|
|
1264
|
+
res = @view[0, 2]
|
|
1265
|
+
@view = @view[2...@view.length]
|
|
1266
|
+
return res
|
|
1267
|
+
end
|
|
1268
|
+
end
|
|
1269
|
+
|
|
1270
|
+
class BaseTypes
|
|
1271
|
+
def self.method_missing(method_name)
|
|
1272
|
+
case method_name.to_s
|
|
1273
|
+
when 'null'
|
|
1274
|
+
return NullClass.new
|
|
1275
|
+
when 'empty'
|
|
1276
|
+
return EmptyClass.new
|
|
1277
|
+
when 'bool'
|
|
1278
|
+
return BoolClass.new
|
|
1279
|
+
when 'int'
|
|
1280
|
+
return IntClass.new
|
|
1281
|
+
when 'reserved'
|
|
1282
|
+
return ReservedClass.new
|
|
1283
|
+
when 'nat'
|
|
1284
|
+
return NatClass.new
|
|
1285
|
+
when 'text'
|
|
1286
|
+
return TextClass.new
|
|
1287
|
+
when 'principal'
|
|
1288
|
+
return PrincipalClass.new
|
|
1289
|
+
when 'float32'
|
|
1290
|
+
return FloatClass.new(32)
|
|
1291
|
+
when 'float64'
|
|
1292
|
+
return FloatClass.new(64)
|
|
1293
|
+
when 'int8'
|
|
1294
|
+
return FixedIntClass.new(8)
|
|
1295
|
+
when 'int16'
|
|
1296
|
+
return FixedIntClass.new(16)
|
|
1297
|
+
when 'int32'
|
|
1298
|
+
return FixedIntClass.new(32)
|
|
1299
|
+
when 'int64'
|
|
1300
|
+
return FixedIntClass.new(64)
|
|
1301
|
+
when 'nat8'
|
|
1302
|
+
return FixedNatClass.new(8)
|
|
1303
|
+
when 'nat16'
|
|
1304
|
+
return FixedNatClass.new(16)
|
|
1305
|
+
when 'nat32'
|
|
1306
|
+
return FixedNatClass.new(32)
|
|
1307
|
+
when 'nat64'
|
|
1308
|
+
return FixedNatClass.new(64)
|
|
1309
|
+
else
|
|
1310
|
+
puts "Method #{method_name} is not defined"
|
|
1311
|
+
end
|
|
1312
|
+
end
|
|
1313
|
+
|
|
1314
|
+
def self.tuple(*types)
|
|
1315
|
+
TupleClass.new(*types)
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
def self.vec(t)
|
|
1319
|
+
VecClass.new(t)
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1322
|
+
def self.opt(t)
|
|
1323
|
+
OptClass.new(t)
|
|
1324
|
+
end
|
|
1325
|
+
|
|
1326
|
+
def self.record(t)
|
|
1327
|
+
RecordClass.new(t)
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
def self.variant(fields)
|
|
1331
|
+
VariantClass.new(fields)
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
def self.rec
|
|
1335
|
+
RecClass.new
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
def self.func(args, ret, annotations)
|
|
1339
|
+
FuncClass.new(args, ret, annotations)
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
def self.service(t)
|
|
1343
|
+
ServiceClass.new(t)
|
|
1344
|
+
end
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1347
|
+
def self.leb128u_decode(pipe)
|
|
1348
|
+
res = StringIO.new
|
|
1349
|
+
loop do
|
|
1350
|
+
byte = safe_read_byte(pipe)
|
|
1351
|
+
res.putc(byte.hex)
|
|
1352
|
+
break if byte < '80' || pipe.length.zero?
|
|
1353
|
+
end
|
|
1354
|
+
|
|
1355
|
+
LEB128.decode_signed(res)
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
def self.leb128i_decode(pipe)
|
|
1359
|
+
length = pipe.buffer.length
|
|
1360
|
+
count = 0
|
|
1361
|
+
(0...length).each do |i|
|
|
1362
|
+
count = i
|
|
1363
|
+
if pipe.buffer[i] < '80' # 0x80
|
|
1364
|
+
if pipe.buffer[i] < '40' # 0x40
|
|
1365
|
+
return leb128u_decode(pipe)
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1368
|
+
break
|
|
1369
|
+
end
|
|
1370
|
+
end
|
|
1371
|
+
res = StringIO.new
|
|
1372
|
+
res.putc(safe_read(pipe, count + 1).hex)
|
|
1373
|
+
LEB128.decode_signed(res)
|
|
1374
|
+
end
|
|
1375
|
+
|
|
1376
|
+
def self.safe_read(pipe, num)
|
|
1377
|
+
raise ArgumentError, 'unexpected end of buffer' if pipe.length < num
|
|
1378
|
+
|
|
1379
|
+
pipe.read(num)
|
|
1380
|
+
end
|
|
1381
|
+
|
|
1382
|
+
def self.safe_read_byte(pipe)
|
|
1383
|
+
raise ArgumentError, 'unexpected end of buffer' if pipe.length < 1
|
|
1384
|
+
|
|
1385
|
+
pipe.readbyte
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
def self.leb128_string_hex(p_str)
|
|
1389
|
+
LEB128.encode_signed(p_str).string.to_hex
|
|
1390
|
+
end
|
|
1391
|
+
|
|
1392
|
+
def self.unicode_to_hex(u_code)
|
|
1393
|
+
u_code.to_hex
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
def self.build_type(raw_table, table, entry)
|
|
1397
|
+
ty = entry[0]
|
|
1398
|
+
if ty == TypeIds::Vec
|
|
1399
|
+
if ty >= raw_table.length
|
|
1400
|
+
raise ValueError, 'type index out of range'
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
t = get_type(raw_table, table, entry[1])
|
|
1404
|
+
if t.nil?
|
|
1405
|
+
t = table[t]
|
|
1406
|
+
end
|
|
1407
|
+
return BaseTypes::vec(t)
|
|
1408
|
+
elsif ty == TypeIds::Opt
|
|
1409
|
+
if ty >= raw_table.length
|
|
1410
|
+
raise ValueError, 'type index out of range'
|
|
1411
|
+
end
|
|
1412
|
+
|
|
1413
|
+
t = get_type(raw_table, table, entry[1])
|
|
1414
|
+
if t.nil?
|
|
1415
|
+
t = table[t]
|
|
1416
|
+
end
|
|
1417
|
+
return BaseTypes::opt(t)
|
|
1418
|
+
elsif ty == TypeIds::Record
|
|
1419
|
+
fields = {}
|
|
1420
|
+
entry[1].each do |hash, t|
|
|
1421
|
+
name = "_#{hash.to_s}_"
|
|
1422
|
+
if t >= raw_table.length
|
|
1423
|
+
raise ValueError, 'type index out of range'
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1426
|
+
temp = get_type(raw_table, table, t)
|
|
1427
|
+
fields[name] = temp
|
|
1428
|
+
end
|
|
1429
|
+
record = BaseTypes::record(fields)
|
|
1430
|
+
tup = record.try_as_tuple()
|
|
1431
|
+
if tup.is_a?(Array)
|
|
1432
|
+
return BaseTypes::tuple(*tup)
|
|
1433
|
+
else
|
|
1434
|
+
return record
|
|
1435
|
+
end
|
|
1436
|
+
elsif ty == TypeIds::Variant
|
|
1437
|
+
fields = {}
|
|
1438
|
+
entry[1].each do |hash, t|
|
|
1439
|
+
name = "_#{hash.to_s}_"
|
|
1440
|
+
if t >= raw_table.length
|
|
1441
|
+
raise ValueError, 'type index out of range'
|
|
1442
|
+
end
|
|
1443
|
+
|
|
1444
|
+
temp = get_type(raw_table, table, t)
|
|
1445
|
+
fields[name] = temp
|
|
1446
|
+
end
|
|
1447
|
+
return BaseTypes::variant(fields)
|
|
1448
|
+
elsif ty == TypeIds::Func
|
|
1449
|
+
return BaseTypes::func([], [], [])
|
|
1450
|
+
elsif ty == TypeIds::Service
|
|
1451
|
+
return BaseTypes::service({})
|
|
1452
|
+
else
|
|
1453
|
+
raise ValueError, "Illegal op_code: #{ty}"
|
|
1454
|
+
end
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
def self.read_type_table(pipe)
|
|
1458
|
+
type_table = []
|
|
1459
|
+
|
|
1460
|
+
type_table_len = leb128u_decode(pipe).to_i
|
|
1461
|
+
type_table_len.times do
|
|
1462
|
+
ty = leb128i_decode(pipe)
|
|
1463
|
+
|
|
1464
|
+
if [TypeIds::Opt, TypeIds::Vec].include?(ty)
|
|
1465
|
+
t = leb128i_decode(pipe)
|
|
1466
|
+
type_table << [ty, t]
|
|
1467
|
+
elsif [TypeIds::Record, TypeIds::Variant].include?(ty)
|
|
1468
|
+
fields = []
|
|
1469
|
+
obj_length = leb128u_decode(pipe)
|
|
1470
|
+
prev_hash = -1
|
|
1471
|
+
|
|
1472
|
+
obj_length.times do
|
|
1473
|
+
hash = leb128u_decode(pipe)
|
|
1474
|
+
|
|
1475
|
+
if hash >= 2**32
|
|
1476
|
+
raise ValueError, 'field id out of 32-bit range'
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
if prev_hash.is_a?(Integer) && prev_hash >= hash
|
|
1480
|
+
raise ValueError, 'field id collision or not sorted'
|
|
1481
|
+
end
|
|
1482
|
+
|
|
1483
|
+
prev_hash = hash
|
|
1484
|
+
t = leb128i_decode(pipe)
|
|
1485
|
+
fields << [hash, t]
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1488
|
+
type_table << [ty, fields]
|
|
1489
|
+
elsif ty == TypeIds::Func
|
|
1490
|
+
2.times do
|
|
1491
|
+
fun_len = leb128u_decode(pipe)
|
|
1492
|
+
fun_len.times { leb128i_decode(pipe) }
|
|
1493
|
+
end
|
|
1494
|
+
|
|
1495
|
+
ann_len = leb128u_decode(pipe)
|
|
1496
|
+
safe_read(pipe, ann_len)
|
|
1497
|
+
type_table << [ty, nil]
|
|
1498
|
+
elsif ty == TypeIds::Service
|
|
1499
|
+
serv_len = leb128u_decode(pipe)
|
|
1500
|
+
|
|
1501
|
+
serv_len.times do
|
|
1502
|
+
l = leb128u_decode(pipe)
|
|
1503
|
+
safe_read(pipe, l)
|
|
1504
|
+
leb128i_decode(pipe)
|
|
1505
|
+
end
|
|
1506
|
+
|
|
1507
|
+
type_table << [ty, nil]
|
|
1508
|
+
else
|
|
1509
|
+
raise ValueError, "Illegal op_code: #{ty}"
|
|
1510
|
+
end
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
raw_list = []
|
|
1514
|
+
types_len = leb128u_decode(pipe).to_i
|
|
1515
|
+
|
|
1516
|
+
types_len.times do
|
|
1517
|
+
raw_list << leb128i_decode(pipe)
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
[type_table, raw_list]
|
|
1521
|
+
end
|
|
1522
|
+
|
|
1523
|
+
def self.get_type(raw_table, table, t)
|
|
1524
|
+
if t < -24
|
|
1525
|
+
raise ValueError, 'not supported type'
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1528
|
+
if t < 0
|
|
1529
|
+
case t
|
|
1530
|
+
when -1
|
|
1531
|
+
return BaseTypes.null
|
|
1532
|
+
when -2
|
|
1533
|
+
return BaseTypes.bool
|
|
1534
|
+
when -3
|
|
1535
|
+
return BaseTypes.nat
|
|
1536
|
+
when -4
|
|
1537
|
+
return BaseTypes.int
|
|
1538
|
+
when -5
|
|
1539
|
+
return BaseTypes.nat8
|
|
1540
|
+
when -6
|
|
1541
|
+
return BaseTypes.nat16
|
|
1542
|
+
when -7
|
|
1543
|
+
return BaseTypes.nat32
|
|
1544
|
+
when -8
|
|
1545
|
+
return BaseTypes.nat64
|
|
1546
|
+
when -9
|
|
1547
|
+
return BaseTypes.int8
|
|
1548
|
+
when -10
|
|
1549
|
+
return BaseTypes.int16
|
|
1550
|
+
when -11
|
|
1551
|
+
return BaseTypes.int32
|
|
1552
|
+
when -12
|
|
1553
|
+
return BaseTypes.int64
|
|
1554
|
+
when -13
|
|
1555
|
+
return BaseTypes.float32
|
|
1556
|
+
when -14
|
|
1557
|
+
return BaseTypes.float64
|
|
1558
|
+
when -15
|
|
1559
|
+
return BaseTypes.text
|
|
1560
|
+
when -16
|
|
1561
|
+
return BaseTypes.reserved
|
|
1562
|
+
when -17
|
|
1563
|
+
return BaseTypes.empty
|
|
1564
|
+
when -24
|
|
1565
|
+
return BaseTypes.principal
|
|
1566
|
+
else
|
|
1567
|
+
raise ValueError, "Illegal op_code: #{t}"
|
|
1568
|
+
end
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
if t >= raw_table.length
|
|
1572
|
+
raise ValueError, 'type index out of range'
|
|
1573
|
+
end
|
|
1574
|
+
|
|
1575
|
+
return table[t]
|
|
1576
|
+
end
|
|
1577
|
+
|
|
1578
|
+
# params = [{type, value}]
|
|
1579
|
+
# data = b'DIDL' + len(params) + encoded types + encoded values
|
|
1580
|
+
def self.encode(params)
|
|
1581
|
+
arg_types = []
|
|
1582
|
+
args = []
|
|
1583
|
+
params.each do |p|
|
|
1584
|
+
arg_types << p[:type]
|
|
1585
|
+
args << p[:value]
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1588
|
+
if arg_types.length != args.length
|
|
1589
|
+
raise ValueError, 'Wrong number of message arguments'
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
typetable = TypeTable.new
|
|
1593
|
+
|
|
1594
|
+
arg_types.each do |item|
|
|
1595
|
+
item.build_type_table(typetable)
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
pre = unicode_to_hex(PREFIX)
|
|
1599
|
+
table = unicode_to_hex(typetable.encode())
|
|
1600
|
+
length = leb128_string_hex(args.length)
|
|
1601
|
+
|
|
1602
|
+
typs = ''
|
|
1603
|
+
arg_types.each do |t|
|
|
1604
|
+
typs += unicode_to_hex(t.encode_type(typetable))
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
vals = ''
|
|
1608
|
+
args.each_with_index do |arg, i|
|
|
1609
|
+
t = arg_types[i]
|
|
1610
|
+
unless t.covariant(args[i])
|
|
1611
|
+
raise TypeError, "Invalid #{t.display} argument: #{args[i]}"
|
|
1612
|
+
end
|
|
1613
|
+
|
|
1614
|
+
vals += unicode_to_hex(t.encode_value(args[i]))
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
return pre + table + length + typs + vals
|
|
1618
|
+
end
|
|
1619
|
+
|
|
1620
|
+
# decode a bytes value
|
|
1621
|
+
# def decode(retTypes, data):
|
|
1622
|
+
def self.decode(data, ret_types = nil)
|
|
1623
|
+
pipe = Pipe.new(data)
|
|
1624
|
+
if data.length < PREFIX.length
|
|
1625
|
+
raise ValueError, 'Message length smaller than prefix number'
|
|
1626
|
+
end
|
|
1627
|
+
|
|
1628
|
+
prefix_buffer = safe_read(pipe, PREFIX.length).hex2str
|
|
1629
|
+
|
|
1630
|
+
if prefix_buffer != PREFIX
|
|
1631
|
+
raise ValueError, "Wrong prefix:#{prefix_buffer}expected prefix: DIDL"
|
|
1632
|
+
end
|
|
1633
|
+
|
|
1634
|
+
raw_table, raw_types = read_type_table(pipe)
|
|
1635
|
+
|
|
1636
|
+
if ret_types
|
|
1637
|
+
if ret_types.class != Array
|
|
1638
|
+
ret_types = [ret_types]
|
|
1639
|
+
end
|
|
1640
|
+
if raw_types.length < ret_types.length
|
|
1641
|
+
raise ValueError, 'Wrong number of return value'
|
|
1642
|
+
end
|
|
1643
|
+
end
|
|
1644
|
+
|
|
1645
|
+
table = []
|
|
1646
|
+
raw_table.length.times do
|
|
1647
|
+
table.append(BaseTypes.rec)
|
|
1648
|
+
end
|
|
1649
|
+
|
|
1650
|
+
raw_table.each_with_index do |entry, i|
|
|
1651
|
+
t = build_type(raw_table, table, entry)
|
|
1652
|
+
table[i].fill(t)
|
|
1653
|
+
end
|
|
1654
|
+
|
|
1655
|
+
types = []
|
|
1656
|
+
raw_types.each do |t|
|
|
1657
|
+
types.append(get_type(raw_table, table, t))
|
|
1658
|
+
end
|
|
1659
|
+
|
|
1660
|
+
outputs = []
|
|
1661
|
+
types.each_with_index do |t, i|
|
|
1662
|
+
outputs.append({
|
|
1663
|
+
'type' => t.name,
|
|
1664
|
+
'value' => t.decode_value(pipe, types[i])
|
|
1665
|
+
})
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
return outputs
|
|
1669
|
+
end
|
|
1670
|
+
end
|
|
1671
|
+
end
|