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