literal 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d4ade41b16e56d3e05c85771d12ffedffa1e5d0c33998890c1fdd0b8b8503bf
4
- data.tar.gz: 7bb21c5e0ab2318825dd19efe878f38db2469f3a6f500615ebf2300723b7438f
3
+ metadata.gz: d40ba211b6f7b2ad3dad97feb118d3742b43dbd2f1773daa8d6979f597cbf428
4
+ data.tar.gz: 1fb316fac766b9b25041c2bc201c8ddaed8d3e59ed5f5aec9c7f93f0306df921
5
5
  SHA512:
6
- metadata.gz: e56f4aaefec78d299254174dcf6a5aded7cb59970291ef55bdb3a88392c230d26efe07c8a18471c9484acd5e6f477f63b6639e7accf712ca7c9aad18720cd84f
7
- data.tar.gz: a60595864a2f267ded92ca14603eb74b0b42deddfa2167fd582e5ebfaee83f0348569d498755e03e088a83ff647149c1159d8758fbb3c4a1c4ebada0d43a0571
6
+ metadata.gz: 37fee8ee4d14f41573f5a4ce2d27d3d98bc1b78a54a35d850a41fbeedfc7e1b1f6f8a3533cbb82c35b81212079d4f495ad17cde8651a7b56fff3e6ecb99b5078
7
+ data.tar.gz: ca6fa6e45d9a344880ebbbfba69c82f9444809ad4b6645e89c4cc0c89c58e78ac66d2edf80612cb2084bac0b46b9c0a686458983f47ff5716f4016b9545f723c
@@ -0,0 +1,428 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Array
4
+ class Generic
5
+ include Literal::Type
6
+
7
+ def initialize(type)
8
+ @type = type
9
+ end
10
+
11
+ attr_reader :type
12
+
13
+ def new(*value)
14
+ Literal::Array.new(value, type: @type)
15
+ end
16
+
17
+ alias_method :[], :new
18
+
19
+ def ===(value)
20
+ Literal::Array === value && Literal.subtype?(value.__type__, of: @type)
21
+ end
22
+
23
+ def >=(other)
24
+ case other
25
+ when Literal::Array::Generic
26
+ @type >= other.type
27
+ else
28
+ false
29
+ end
30
+ end
31
+
32
+ def inspect
33
+ "Literal::Array(#{@type.inspect})"
34
+ end
35
+ end
36
+
37
+ include Enumerable
38
+ include Literal::Types
39
+
40
+ def initialize(value, type:)
41
+ Literal.check(actual: value, expected: _Array(type)) do |c|
42
+ c.fill_receiver(receiver: self, method: "#initialize")
43
+ end
44
+
45
+ @__type__ = type
46
+ @__value__ = value
47
+ end
48
+
49
+ def __initialize_without_check__(value, type:)
50
+ @__type__ = type
51
+ @__value__ = value
52
+ self
53
+ end
54
+
55
+ # Used to create a new Literal::Array with the same type and collection type but a new value. The value is not checked.
56
+ def __with__(value)
57
+ Literal::Array.allocate.__initialize_without_check__(
58
+ value,
59
+ type: @__type__,
60
+ )
61
+ end
62
+
63
+ attr_reader :__type__, :__value__
64
+
65
+ def &(other)
66
+ case other
67
+ when ::Array
68
+ __with__(@__value__ & other)
69
+ when Literal::Array
70
+ __with__(@__value__ & other.__value__)
71
+ else
72
+ raise ArgumentError.new("Cannot perform bitwise AND with #{other.class.name}.")
73
+ end
74
+ end
75
+
76
+ def *(times)
77
+ case times
78
+ when String
79
+ @__value__ * times
80
+ else
81
+ __with__(@__value__ * times)
82
+ end
83
+ end
84
+
85
+ def +(other)
86
+ case other
87
+ when ::Array
88
+ Literal.check(actual: other, expected: _Array(@__type__)) do |c|
89
+ c.fill_receiver(receiver: self, method: "#+")
90
+ end
91
+
92
+ __with__(@__value__ + other)
93
+ when Literal::Array(@__type__)
94
+ __with__(@__value__ + other.__value__)
95
+ when Literal::Array
96
+ raise Literal::TypeError.new(
97
+ context: Literal::TypeError::Context.new(
98
+ expected: Literal::Array(@__type__),
99
+ actual: other
100
+ )
101
+ )
102
+ else
103
+ raise ArgumentError.new("Cannot perform `+` with #{other.class.name}.")
104
+ end
105
+ end
106
+
107
+ def -(other)
108
+ case other
109
+ when ::Array
110
+ __with__(@__value__ - other)
111
+ when Literal::Array
112
+ __with__(@__value__ - other.__value__)
113
+ else
114
+ raise ArgumentError.new("Cannot perform `-` with #{other.class.name}.")
115
+ end
116
+ end
117
+
118
+ def <<(value)
119
+ Literal.check(actual: value, expected: @__type__) do |c|
120
+ c.fill_receiver(receiver: self, method: "#<<")
121
+ end
122
+
123
+ @__value__ << value
124
+ self
125
+ end
126
+
127
+ def <=>(other)
128
+ case other
129
+ when ::Array
130
+ @__value__ <=> other
131
+ when Literal::Array
132
+ @__value__ <=> other.__value__
133
+ else
134
+ raise ArgumentError.new("Cannot perform `<=>` with #{other.class.name}.")
135
+ end
136
+ end
137
+
138
+ def ==(other)
139
+ Literal::Array === other && @__value__ == other.__value__
140
+ end
141
+
142
+ def [](index)
143
+ @__value__[index]
144
+ end
145
+
146
+ def []=(index, value)
147
+ Literal.check(actual: value, expected: @__type__) do |c|
148
+ c.fill_receiver(receiver: self, method: "#[]=")
149
+ end
150
+
151
+ @__value__[index] = value
152
+ end
153
+
154
+ def all?(...)
155
+ @__value__.all?(...)
156
+ end
157
+
158
+ def any?(...)
159
+ @__value__.any?(...)
160
+ end
161
+
162
+ def assoc(...)
163
+ @__value__.assoc(...)
164
+ end
165
+
166
+ def at(...)
167
+ @__value__.at(...)
168
+ end
169
+
170
+ def bsearch(...)
171
+ @__value__.bsearch(...)
172
+ end
173
+
174
+ def clear(...)
175
+ @__value__.clear(...)
176
+ self
177
+ end
178
+
179
+ def compact
180
+ # @TODO if this is an array of nils, we should return an emtpy array
181
+ __with__(@__value__)
182
+ end
183
+
184
+ def compact!
185
+ # @TODO if this is an array of nils, we should set @__value__ = [] and return self
186
+ nil
187
+ end
188
+
189
+ def count(...)
190
+ @__value__.count(...)
191
+ end
192
+
193
+ def dig(...)
194
+ @__value__.dig(...)
195
+ end
196
+
197
+ def drop(...)
198
+ __with__(@__value__.drop(...))
199
+ end
200
+
201
+ def drop_while(...)
202
+ __with__(@__value__.drop_while(...))
203
+ end
204
+
205
+ def each(...)
206
+ @__value__.each(...)
207
+ end
208
+
209
+ def empty?
210
+ @__value__.empty?
211
+ end
212
+
213
+ alias_method :eql?, :==
214
+
215
+ def filter(...)
216
+ __with__(@__value__.filter(...))
217
+ end
218
+
219
+ def filter!(...)
220
+ @__value__.filter!(...)
221
+ self
222
+ end
223
+
224
+ def first(...)
225
+ @__value__.first(...)
226
+ end
227
+
228
+ def freeze
229
+ @__value__.freeze
230
+ super
231
+ end
232
+
233
+ def insert(index, *value)
234
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
235
+ c.fill_receiver(receiver: self, method: "#insert")
236
+ end
237
+
238
+ @__value__.insert(index, *value)
239
+ self
240
+ end
241
+
242
+ def intersection(*values)
243
+ values.map! do |value|
244
+ case value
245
+ when Literal::Array
246
+ value.__value__
247
+ else
248
+ value
249
+ end
250
+ end
251
+
252
+ __with__(@__value__.intersection(*values))
253
+ end
254
+
255
+ def last(...)
256
+ @__value__.last(...)
257
+ end
258
+
259
+ def length(...)
260
+ @__value__.length(...)
261
+ end
262
+
263
+ def map(type, &block)
264
+ my_type = @__type__
265
+ transform_type = Literal::TRANSFORMS.dig(my_type, block)
266
+
267
+ if transform_type && Literal.subtype?(transform_type, of: my_type)
268
+ Literal::Array.allocate.__initialize_without_check__(
269
+ @__value__.map(&block),
270
+ type:,
271
+ )
272
+ else
273
+ Literal::Array.new(@__value__.map(&block), type:)
274
+ end
275
+ end
276
+
277
+ alias_method :collect, :map
278
+
279
+ # TODO: we can make this faster
280
+ def map!(&)
281
+ new_array = map(@__type__, &)
282
+ @__value__ = new_array.__value__
283
+ self
284
+ end
285
+
286
+ alias_method :collect!, :map!
287
+
288
+ def max(n = nil, &)
289
+ if n
290
+ __with__(@__value__.max(n, &))
291
+ else
292
+ @__value__.max(&)
293
+ end
294
+ end
295
+
296
+ def min(n = nil, &)
297
+ if n
298
+ __with__(@__value__.min(n, &))
299
+ else
300
+ @__value__.min(&)
301
+ end
302
+ end
303
+
304
+ def minmax(...)
305
+ __with__(@__value__.minmax(...))
306
+ end
307
+
308
+ def one?(...)
309
+ @__value__.one?(...)
310
+ end
311
+
312
+ def pop(...)
313
+ @__value__.pop(...)
314
+ end
315
+
316
+ def push(*value)
317
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
318
+ c.fill_receiver(receiver: self, method: "#push")
319
+ end
320
+
321
+ @__value__.push(*value)
322
+ self
323
+ end
324
+
325
+ alias_method :append, :push
326
+
327
+ def reject(...)
328
+ __with__(@__value__.reject(...))
329
+ end
330
+
331
+ def reject!(...)
332
+ @__value__.reject!(...)
333
+ self
334
+ end
335
+
336
+ def replace(value)
337
+ case value
338
+ when Array
339
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
340
+ c.fill_receiver(receiver: self, method: "#replace")
341
+ end
342
+
343
+ @__value__.replace(value)
344
+ when Literal::Array(@__type__)
345
+ @__value__.replace(value.__value__)
346
+ when Literal::Array
347
+ raise Literal::TypeError.new(
348
+ context: Literal::TypeError::Context.new(expected: @__type__, actual: value.__type__)
349
+ )
350
+ else
351
+ raise ArgumentError.new("#replace expects Array argument")
352
+ end
353
+
354
+ self
355
+ end
356
+
357
+ def sample(...)
358
+ @__value__.sample(...)
359
+ end
360
+
361
+ def shift(...)
362
+ @__value__.shift(...)
363
+ end
364
+
365
+ def size(...)
366
+ @__value__.size(...)
367
+ end
368
+
369
+ def sort(...)
370
+ __with__(@__value__.sort(...))
371
+ end
372
+
373
+ def sort!(...)
374
+ @__value__.sort!(...)
375
+ self
376
+ end
377
+
378
+ def to_a
379
+ @__value__.dup
380
+ end
381
+
382
+ alias_method :to_ary, :to_a
383
+
384
+ def uniq
385
+ __with__(@__value__.uniq)
386
+ end
387
+
388
+ def uniq!(...)
389
+ @__value__.uniq!(...) ? self : nil
390
+ end
391
+
392
+ def unshift(value)
393
+ Literal.check(actual: value, expected: @__type__) do |c|
394
+ c.fill_receiver(receiver: self, method: "#unshift")
395
+ end
396
+
397
+ @__value__.unshift(value)
398
+ self
399
+ end
400
+
401
+ alias_method :prepend, :unshift
402
+
403
+ def values_at(*indexes)
404
+ unless @__type__ === nil
405
+ max_value = length - 1
406
+ min_value = -length
407
+
408
+ indexes.each do |index|
409
+ case index
410
+ when Integer
411
+ if index < min_value || index > max_value
412
+ raise IndexError.new("index #{index} out of range")
413
+ end
414
+ when Range
415
+ if index.begin < min_value || index.end > max_value
416
+ raise IndexError.new("index #{index} out of range")
417
+ end
418
+ else
419
+ raise ArgumentError.new("Invalid index: #{index.inspect}")
420
+ end
421
+ end
422
+ end
423
+
424
+ __with__(
425
+ @__value__.values_at(*indexes)
426
+ )
427
+ end
428
+ end
@@ -10,16 +10,6 @@ class Literal::DataStructure
10
10
  object
11
11
  end
12
12
 
13
- def [](key)
14
- instance_variable_get(:"@#{key}")
15
- end
16
-
17
- def []=(key, value)
18
- # TODO: Sync error array w/ generated setter
19
- @literal_properties[key].check(value) { |c| raise NotImplementedError }
20
- instance_variable_set(:"@#{key}", value)
21
- end
22
-
23
13
  def to_h
24
14
  {}
25
15
  end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Flags
4
+ include Enumerable
5
+
6
+ def initialize(value = 0, **new_flags)
7
+ if new_flags.length > 0
8
+ value = self.class.calculate_from_hash(new_flags)
9
+ end
10
+
11
+ @value = value
12
+ freeze
13
+ end
14
+
15
+ def __initialize_from_value__(value)
16
+ @value = value
17
+ freeze
18
+ end
19
+
20
+ attr_reader :value
21
+
22
+ def self.define(**flags)
23
+ raise ArgumentError if frozen?
24
+ unique_values = flags.values
25
+ unique_values.uniq!
26
+
27
+ if unique_values.length != flags.length
28
+ raise Literal::ArgumentError.new("Flags must be unique.")
29
+ end
30
+
31
+ const_set(:FLAGS, flags.dup.freeze)
32
+
33
+ flags.each do |name, bit|
34
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
35
+ # frozen_string_literal: true
36
+
37
+ def #{name}?
38
+ @value & (2 ** #{bit}) > 0
39
+ end
40
+ RUBY
41
+ end
42
+
43
+ freeze
44
+ end
45
+
46
+ # () -> (Integer) -> Literal::Flags
47
+ def self.to_proc
48
+ proc { |value| new(value) }
49
+ end
50
+
51
+ # (Integer) -> String
52
+ def self.calculate_bit_string(value)
53
+ value.to_s(2).rjust(self::BITS, "0")
54
+ end
55
+
56
+ # (Array(Boolean)) -> Integer
57
+ def self.calculate_from_array(array)
58
+ array.reverse_each.with_index.reduce(0) do |value, (bit, index)|
59
+ value | (bit ? 1 << index : 0)
60
+ end
61
+ end
62
+
63
+ # (Hash(Symbol, Boolean)) -> Integer
64
+ def self.calculate_from_hash(hash)
65
+ flags = self::FLAGS
66
+ hash.reduce(0) do |value, (key, bit)|
67
+ value | (bit ? 2 ** flags.fetch(key) : 0)
68
+ end
69
+ end
70
+
71
+ # (Integer) -> Array(Symbol)
72
+ def self.calculate_tokens(value)
73
+ flags = self::FLAGS
74
+ flags.keys.select { |t| value & (2 ** flags.fetch(t)) > 0 }
75
+ end
76
+
77
+ # (Integer) -> Array(Boolean)
78
+ def self.calculate_array(value)
79
+ bits = self::BITS
80
+ Array.new(bits) { |i| (value & (2 ** (bits - 1 - i)) > 0) }
81
+ end
82
+
83
+ # (Array(Symbol)) -> Integer
84
+ def self.calculate_from_tokens(tokens)
85
+ flags = self::FLAGS
86
+ tokens.reduce(0) { |f, t| f | (2 ** flags.fetch(t)) }
87
+ end
88
+
89
+ # (Integer) -> Hash(Symbol, Boolean)
90
+ def self.calculate_hash_from_value(value)
91
+ self::FLAGS.transform_values do |bit|
92
+ (value & (2 ** bit)) > 0
93
+ end
94
+ end
95
+
96
+ # () -> Array(Symbol)
97
+ def self.keys
98
+ @flags.keys
99
+ end
100
+
101
+ # (String) -> Literal::Flags
102
+ def self.from_bit_string(bit_string)
103
+ from_int(bit_string.to_i(2))
104
+ end
105
+
106
+ # (Array(Boolean)) -> Literal::Flags
107
+ def self.from_array(array)
108
+ if array.length != self::BITS
109
+ raise Literal::ArgumentError.new("The array must have #{self::BITS} items.")
110
+ end
111
+
112
+ from_int(calculate_from_array(array))
113
+ end
114
+
115
+ # (Array(Symbol)) -> Literal::Flags
116
+ def self.from_tokens(tokens)
117
+ from_int(calculate_from_tokens(tokens))
118
+ end
119
+
120
+ # (Integer) -> Literal::Flags
121
+ def self.from_int(value)
122
+ allocate.__initialize_from_value__(value)
123
+ end
124
+
125
+ # (String) -> Integer
126
+ def self.unpack_int(value)
127
+ value.unpack1(self::PACKER)
128
+ end
129
+
130
+ # (String) -> Literal::Flags
131
+ def self.unpack(value)
132
+ new(unpack_int(value))
133
+ end
134
+
135
+ # () -> String
136
+ def pack
137
+ [@value].pack(self.class::PACKER)
138
+ end
139
+
140
+ def with(**attributes)
141
+ new_val = attributes.reduce(value) do |value, (k, v)|
142
+ v ? value |= bitmap(k) : value &= ~(bitmap(k))
143
+ value
144
+ end
145
+
146
+ self.class.allocate.__initialize_from_value__(new_val)
147
+ end
148
+
149
+ # () -> String
150
+ def inspect
151
+ to_h.inspect
152
+ end
153
+
154
+ # () -> Hash(Symbol, Boolean)
155
+ def to_h
156
+ self.class.calculate_hash_from_value(@value)
157
+ end
158
+
159
+ def each
160
+ self.class::FLAGS.each do |key, bit|
161
+ yield key, @value & (2 ** bit) > 0
162
+ end
163
+ end
164
+
165
+ # (Symbol) -> Boolean
166
+ def [](key)
167
+ @value & (bitmap(key)) > 0
168
+ end
169
+
170
+ def |(other)
171
+ case other
172
+ when Literal::Flags
173
+ self.class.new(@value | other.value)
174
+ when Integer
175
+ self.class.new(@value | other)
176
+ end
177
+ end
178
+
179
+ def &(other)
180
+ case other
181
+ when Literal::Flags
182
+ self.class.new(@value & other.value)
183
+ when Integer
184
+ self.class.new(@value & other)
185
+ end
186
+ end
187
+
188
+ def to_i
189
+ @value
190
+ end
191
+
192
+ def to_bit_string
193
+ self.class.calculate_bit_string(@value)
194
+ end
195
+
196
+ def to_tokens
197
+ self.class.calculate_tokens(@value)
198
+ end
199
+
200
+ def to_a
201
+ self.class.calculate_array(@value)
202
+ end
203
+
204
+ alias_method :deconstruct, :to_a
205
+
206
+ def deconstruct_keys(keys = nil)
207
+ if keys
208
+ keys.to_h do |key|
209
+ [key, @value & (bitmap(key)) > 0]
210
+ end
211
+ else
212
+ to_h
213
+ end
214
+ end
215
+
216
+ private
217
+
218
+ def bitmap(key)
219
+ 2 ** self.class::FLAGS.fetch(key)
220
+ end
221
+ end
222
+
223
+ class Literal::Flags8 < Literal::Flags
224
+ BYTES = 1
225
+ BITS = BYTES * 8
226
+ PACKER = "C"
227
+ end
228
+
229
+ class Literal::Flags16 < Literal::Flags
230
+ BYTES = 2
231
+ BITS = BYTES * 8
232
+ PACKER = "S"
233
+ end
234
+
235
+ class Literal::Flags32 < Literal::Flags
236
+ BYTES = 4
237
+ BITS = BYTES * 8
238
+ PACKER = "L"
239
+ end
240
+
241
+ class Literal::Flags64 < Literal::Flags
242
+ BYTES = 8
243
+ BITS = BYTES * 8
244
+ PACKER = "Q"
245
+ end