literal 1.0.0 → 1.2.0

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