ton-sdk-ruby 0.0.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,398 @@
1
+ module TonSdkRuby
2
+
3
+ class Hashmap
4
+ attr_reader :hashmap, :key_size
5
+
6
+ def initialize(key_size, options = {})
7
+ serializers = options.fetch(:serializers, {})
8
+ deserializers = options.fetch(:deserializers, {})
9
+
10
+ @hashmap = {}
11
+ @key_size = key_size
12
+ @serialize_key = serializers.fetch(:key, -> (key) { key })
13
+ @serialize_value = serializers.fetch(:value, -> (value) { value })
14
+ @deserialize_key = deserializers.fetch(:key, -> (key) { key })
15
+ @deserialize_value = deserializers.fetch(:value, -> (value) { value })
16
+ end
17
+
18
+ def each
19
+ result = []
20
+ @hashmap.each do |k, v|
21
+ key = deserialize_key(k.chars.map(&:to_i))
22
+ value = deserialize_value(v)
23
+
24
+ result << (yield [key, value])
25
+ end
26
+ result
27
+ end
28
+
29
+ def get(key)
30
+ k = serialize_key(key).join('')
31
+ v = @hashmap[k]
32
+
33
+ v.nil? ? nil : deserialize_value(v)
34
+ end
35
+
36
+ def has(key)
37
+ !get(key).nil?
38
+ end
39
+
40
+ def set(key, value)
41
+ k = serialize_key(key).join('')
42
+ v = serialize_value(value)
43
+ @hashmap[k] = v
44
+
45
+ self
46
+ end
47
+
48
+ def add(key, value)
49
+ has(key) ? self : set(key, value)
50
+ end
51
+
52
+ def replace(key, value)
53
+ has(key) ? set(key, value) : self
54
+ end
55
+
56
+ def get_set(key, value)
57
+ prev = get(key)
58
+ set(key, value)
59
+ prev
60
+ end
61
+
62
+ def get_add(key, value)
63
+ prev = get(key)
64
+ add(key, value)
65
+ prev
66
+ end
67
+
68
+ def get_replace(key, value)
69
+ prev = get(key)
70
+ replace(key, value)
71
+ prev
72
+ end
73
+
74
+ def delete(key)
75
+ k = serialize_key(key).join('')
76
+ hashmap.delete(k)
77
+ self
78
+ end
79
+
80
+ def is_empty?
81
+ hashmap.size == 0
82
+ end
83
+
84
+ def for_each(&callback)
85
+ self.each { |key, value| callback.call(key, value) }
86
+ end
87
+
88
+ def get_raw(key)
89
+ hashmap[key.join('')]
90
+ end
91
+
92
+ def set_raw(key, value)
93
+ hashmap[key.join('')] = value
94
+ self
95
+ end
96
+
97
+ def sort_hashmap
98
+ sorted = hashmap.reduce([]) do |acc, (bitstring, value)|
99
+ key = bitstring.chars.map(&:to_i)
100
+ # Sort keys by DESC to serialize labels correctly later
101
+ order = bitstring.to_i(2)
102
+ lt = acc.find_index { |el| order > el[:order] }
103
+ index = lt ? lt : acc.length
104
+
105
+ acc.insert(index, { order: order, key: key, value: value })
106
+ end
107
+
108
+ sorted.map { |el| [el[:key], el[:value]] }
109
+ end
110
+
111
+ def serialize
112
+ nodes = sort_hashmap
113
+
114
+ if nodes.empty?
115
+ raise 'Hashmap: can\'t be empty. It must contain at least 1 key-value pair.'
116
+ end
117
+
118
+ Hashmap.serialize_edge(nodes)
119
+ end
120
+
121
+ def self.serialize_edge(nodes)
122
+ # hme_empty$0
123
+ if nodes.empty?
124
+ label = serialize_label_short([])
125
+
126
+ return Builder.new
127
+ .store_bits(label)
128
+ .cell
129
+ end
130
+
131
+ edge = Builder.new
132
+ label = serialize_label(nodes)
133
+
134
+ edge.store_bits(label)
135
+
136
+ # hmn_leaf#_
137
+ if nodes.length == 1
138
+ leaf = serialize_leaf(nodes[0])
139
+
140
+ edge.store_slice(leaf.parse)
141
+ end
142
+
143
+ # hmn_fork#_
144
+ if nodes.length > 1
145
+ # Left edge can be empty, anyway we need to create hme_empty$0 to support right one
146
+ left_nodes, right_nodes = serialize_fork(nodes)
147
+ left_edge = serialize_edge(left_nodes)
148
+
149
+ edge.store_ref(left_edge)
150
+
151
+ unless right_nodes.empty?
152
+ right_edge = serialize_edge(right_nodes)
153
+
154
+ edge.store_ref(right_edge)
155
+ end
156
+ end
157
+
158
+ edge.cell
159
+ end
160
+
161
+ def self.serialize_fork(nodes)
162
+ # Serialize nodes to edges
163
+ nodes.reduce([[], []]) do |acc, (key, value)|
164
+ # Sort nodes by left/right edges
165
+ acc[key.shift].push([key, value])
166
+
167
+ acc
168
+ end
169
+ end
170
+
171
+ def self.serialize_leaf(node)
172
+ node[1]
173
+ end
174
+
175
+ def self.serialize_label(nodes)
176
+ # Each label can always be serialized in at least two different fashions, using
177
+ # hml_short or hml_long constructors. Usually the shortest serialization (and
178
+ # in the case of a tie—the lexicographically smallest among the shortest) is
179
+ # preferred and is generated by TVM hashmap primitives, while the other
180
+ # variants are still considered valid.
181
+
182
+ # Get nodes keys
183
+ first = nodes[0][0]
184
+ last = nodes[nodes.length - 1][0]
185
+ # m = length at most possible bits of n (key)
186
+ m = first.length
187
+
188
+ same_bits_index = nil
189
+ first.each_with_index do |el, index|
190
+ if el != last[index]
191
+ same_bits_index = index
192
+ break
193
+ end
194
+ end
195
+
196
+ same_bits_length = same_bits_index.nil? ? first.length : same_bits_index
197
+
198
+ if first[0] != last[0] || m == 0
199
+ # hml_short for zero most possible bits
200
+ return serialize_label_short([])
201
+ end
202
+
203
+ label = first[0, same_bits_length]
204
+ repeated = label.join('').match(/(^0+)|(^1+)/)[0].split('').map { |b| b.to_i }
205
+ label_short = serialize_label_short(label)
206
+ label_long = serialize_label_long(label, m)
207
+ label_same = nodes.length > 1 && repeated.length > 1 ? serialize_label_same(repeated, m) : nil
208
+
209
+ labels = [
210
+ { bits: label.length, label: label_short },
211
+ { bits: label.length, label: label_long },
212
+ { bits: repeated.length, label: label_same }
213
+ ].reject { |el| el[:label].nil? }
214
+
215
+ # Sort labels by their length
216
+ labels.sort_by! { |el| el[:label].length }
217
+
218
+ # Get most compact label
219
+ choosen = labels[0]
220
+
221
+ # Remove label bits from nodes keys
222
+ nodes.each { |key, _| key.shift(choosen[:bits]) }
223
+
224
+ choosen[:label]
225
+ end
226
+
227
+ def self.serialize_label_short(bits)
228
+ label = Builder.new
229
+
230
+ label.store_bit(0)
231
+ .store_bits(bits.map { 1 })
232
+ .store_bit(0)
233
+ .store_bits(bits)
234
+
235
+ label.bits
236
+ end
237
+
238
+ def self.serialize_label_long(bits, m)
239
+ label = Builder.new
240
+
241
+ label.store_bits([1, 0])
242
+ .store_uint(bits.length, Math.log2(m + 1).ceil)
243
+ .store_bits(bits)
244
+
245
+ label.bits
246
+ end
247
+
248
+ def self.serialize_label_same(bits, m)
249
+ label = Builder.new
250
+
251
+ label.store_bits([1, 1])
252
+ .store_bit(bits[0])
253
+ .store_uint(bits.length, Math.log2(m + 1).ceil)
254
+
255
+ label.bits
256
+ end
257
+
258
+ def self.deserialize(key_size, slice, options = {})
259
+ if slice.bits.length < 2
260
+ raise 'Hashmap: can\'t be empty. It must contain at least 1 key-value pair.'
261
+ end
262
+
263
+ hashmap = Hashmap.new(key_size, options)
264
+ nodes = deserialize_edge(slice, key_size)
265
+
266
+ nodes.each do |key, value|
267
+ hashmap.set_raw(key, value)
268
+ end
269
+
270
+ hashmap
271
+ end
272
+
273
+ def self.deserialize_edge(edge, key_size, key = [])
274
+ nodes = []
275
+
276
+ key.concat(deserialize_label(edge, key_size - key.length))
277
+
278
+ if key.length == key_size
279
+ value = Builder.new.store_slice(edge).cell
280
+
281
+ return nodes.concat([[key, value]])
282
+ end
283
+
284
+ edge.refs.each_with_index do |_r, i|
285
+ fork_edge = edge.load_ref.parse
286
+ fork_key = key + [i]
287
+
288
+ nodes.concat(deserialize_edge(fork_edge, key_size, fork_key))
289
+ end
290
+
291
+ nodes
292
+ end
293
+
294
+ def self.deserialize_label(edge, m)
295
+ # m = length at most possible bits of n (key)
296
+
297
+ # hml_short$0
298
+ if edge.load_bit == 0
299
+ return deserialize_label_short(edge)
300
+ end
301
+
302
+ # hml_long$10
303
+ if edge.load_bit == 0
304
+ return deserialize_label_long(edge, m)
305
+ end
306
+
307
+ # hml_same$11
308
+ deserialize_label_same(edge, m)
309
+ end
310
+
311
+ def self.deserialize_label_short(edge)
312
+ length = edge.bits.index(0)
313
+ edge.skip(length + 1)
314
+ edge.load_bits(length)
315
+ end
316
+
317
+ def self.deserialize_label_long(edge, m)
318
+ length = edge.load_uint(Math.log2(m + 1).ceil)
319
+ edge.load_bits(length)
320
+ end
321
+
322
+ def self.deserialize_label_same(edge, m)
323
+ repeated = edge.load_bit
324
+ length = edge.load_uint(Math.log2(m + 1).ceil)
325
+ Array.new(length) { repeated }
326
+ end
327
+
328
+ def cell
329
+ serialize
330
+ end
331
+
332
+ def self.parse(key_size, slice, options = nil)
333
+ deserialize(key_size, slice, options)
334
+ end
335
+
336
+ private
337
+
338
+ def serialize_key(key)
339
+ @serialize_key.call(key)
340
+ end
341
+
342
+ def serialize_value(value)
343
+ @serialize_value.call(value)
344
+ end
345
+
346
+ def deserialize_key(key)
347
+ @deserialize_key.call(key)
348
+ end
349
+
350
+ def deserialize_value(value)
351
+ @deserialize_value.call(value)
352
+ end
353
+ end
354
+
355
+ class HashmapE < Hashmap
356
+ def initialize(key_size, options = nil)
357
+ super(key_size, options)
358
+ end
359
+
360
+ protected
361
+
362
+ def serialize
363
+ nodes = sort_hashmap
364
+ result = Builder.new
365
+
366
+ if nodes.empty?
367
+ result.store_bit(0).cell
368
+ else
369
+ result.store_bit(1).store_ref(HashmapE.serialize_edge(nodes)).cell
370
+ end
371
+ end
372
+
373
+ def self.deserialize(key_size, slice, options = nil)
374
+ if slice.bits.length != 1
375
+ raise 'HashmapE: bad hashmap size flag.'
376
+ end
377
+
378
+ if slice.load_bit == 0
379
+ HashmapE.new(key_size, options)
380
+ else
381
+ hashmap = HashmapE.new(key_size, options)
382
+ edge = slice.load_ref.parse
383
+ nodes = Hashmap.deserialize_edge(edge, key_size)
384
+
385
+ nodes.each do |key, value|
386
+ hashmap.set_raw(key, value)
387
+ end
388
+
389
+ hashmap
390
+ end
391
+ end
392
+
393
+ def self.parse(key_size, slice, options = nil)
394
+ deserialize(key_size, slice, options)
395
+ end
396
+ end
397
+
398
+ end
@@ -0,0 +1,46 @@
1
+ module TonSdkRuby
2
+ class Mask
3
+
4
+ attr_accessor :hash_index, :hash_count, :value
5
+
6
+ def initialize(mask)
7
+ if mask.class.to_s.downcase == "mask"
8
+ @value = mask.value
9
+ elsif mask.class.to_s.downcase == "integer"
10
+ @value = mask
11
+ end
12
+
13
+ @hash_index = count_set_bits(value)
14
+ @hash_count = @hash_index + 1
15
+ end
16
+
17
+ def level
18
+ 32 - clz(value)
19
+ end
20
+
21
+ def is_significant(level)
22
+ level == 0 || (self.value >> (level - 1)) % 2 != 0
23
+ end
24
+
25
+ def apply(level)
26
+ Mask.new(self.value & ((1 << level) - 1))
27
+ end
28
+
29
+ private
30
+
31
+ def clz(number, size = 32)
32
+ bits_string = number.to_i.to_s(2)
33
+ if bits_string.size > size
34
+ bits_string.slice((bits_string.size - size)..bits_string.size)
35
+ else
36
+ size - bits_string.size
37
+ end
38
+ end
39
+
40
+ def count_set_bits(n)
41
+ n = n - ((n >> 1) & 0x55555555)
42
+ n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
43
+ ((n + (n >> 4) & 0xF0F0F0F) * 0x1010101) >> 24
44
+ end
45
+ end
46
+ end