0xfacet-typed 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a0ed00364240e4bb50034acabd0cec233cd24cae34ccda46f7e245a52d43b666
4
+ data.tar.gz: 359636ba089c58bf1fdd97d45b425dec14d63ee30f58815d9a268cfba5a3fa8e
5
+ SHA512:
6
+ metadata.gz: 2bb991ecfa5a60979e4998e13613dc9400df98d09ee892d5e6747107d3675944b9178c072b1c3ae39d54d3ce1e7f7b06f523312c24d35e5efe1e8c7b04649c58
7
+ data.tar.gz: 70c0e53db248bb2f12353059bf1d42adc468d7d2d7bb27b8f25b17df30d7143df6be72ce621df153506e388b3d888dfe89fe77b8e224f4cb7e00b783a27dafac
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2023-11-16
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/0xfacet/typed.rb
6
+ lib/0xfacet/typed/array_type.rb
7
+ lib/0xfacet/typed/attr_public_read_private_write.rb
8
+ lib/0xfacet/typed/contract_errors.rb
9
+ lib/0xfacet/typed/contract_type.rb
10
+ lib/0xfacet/typed/mapping_type.rb
11
+ lib/0xfacet/typed/type.rb
12
+ lib/0xfacet/typed/typed_variable.rb
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # 0xFacet Typed
2
+
3
+ 0xfacet-typed - solidity-like value and reference types for rubidity o.g.
4
+
5
+
6
+ * home :: [github.com/s6ruby/rubidity.review](https://github.com/s6ruby/rubidity.review)
7
+ * bugs :: [github.com/s6ruby/rubidity.review/issues](https://github.com/s6ruby/rubidity/issues)
8
+ * gem :: [rubygems.org/gems/0xfacet-typed](https://rubygems.org/gems/0xfacet-typed)
9
+ * rdoc :: [rubydoc.info/gems/0xfacet-typed](http://rubydoc.info/gems/0xfacet-typed)
10
+
11
+
12
+
13
+ ## About
14
+
15
+ What's happening herè?
16
+
17
+ The idea is to look at the facet vm code as-is (that is, NOT suggesting new or alternate syntax and semantics) in the review / commentary
18
+ and start to (re)package / modular-ize
19
+ code in "place holder" gems (waiting for adoption by the founders) such as 0xfacet and 0xfacet-typed and 0xfacet-rubidity.
20
+
21
+ See [Rubidity O.G. (Dumb Contracts) Public Code Review / (More) Tests / Gems & More »](https://github.com/s6ruby/rubidity.review)
22
+
23
+
24
+
25
+
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require 'hoe'
2
+
3
+ # require './lib/0xfacet/typed/version.rb'
4
+
5
+
6
+ Hoe.spec '0xfacet-typed' do
7
+
8
+ self.version = '0.0.1'
9
+
10
+ self.summary = '0xfacet-typed - solidity-like value and reference types for rubidity o.g.'
11
+ self.description = summary
12
+
13
+ self.urls = { home: 'https://github.com/s6ruby/rubidity.review' }
14
+
15
+ self.author = 'Gerald Bauer'
16
+ self.email = 'gerald.bauer@gmail.com'
17
+
18
+ # switch extension to .markdown for gihub formatting
19
+ self.readme_file = 'README.md'
20
+ self.history_file = 'CHANGELOG.md'
21
+
22
+ self.extra_deps = [
23
+ ]
24
+
25
+
26
+ self.licenses = ['Public Domain']
27
+
28
+ self.spec_extras = {
29
+ required_ruby_version: '>= 2.3'
30
+ }
31
+ end
@@ -0,0 +1,89 @@
1
+ class ArrayType < TypedVariable
2
+ def initialize(...)
3
+ super(...)
4
+ value.on_change = on_change
5
+ end
6
+
7
+ def serialize
8
+ value.data.map(&:serialize)
9
+ end
10
+
11
+ class Proxy
12
+ extend AttrPublicReadPrivateWrite
13
+
14
+ attr_accessor :on_change
15
+ attr_public_read_private_write :value_type, :data
16
+
17
+ def ==(other)
18
+ return false unless other.is_a?(self.class)
19
+
20
+ other.value_type == value_type &&
21
+ other.data == data
22
+ end
23
+
24
+ def initialize(
25
+ initial_value = [],
26
+ value_type:,
27
+ initial_length: nil,
28
+ on_change: nil
29
+ )
30
+ unless value_type.is_value_type?
31
+ raise VariableTypeError.new("Only value types can me array elements")
32
+ end
33
+
34
+ self.value_type = value_type
35
+ self.data = initial_value
36
+
37
+ if initial_length
38
+ amount_to_pad = initial_length - data.size
39
+
40
+ amount_to_pad.times do
41
+ data << TypedVariable.create(value_type)
42
+ end
43
+ end
44
+
45
+ self.on_change = on_change
46
+ end
47
+
48
+ def [](index)
49
+ index_var = TypedVariable.create_or_validate(:uint256, index, on_change: on_change)
50
+
51
+ raise "Index out of bounds" if index_var >= data.size
52
+
53
+ value = data[index_var]
54
+ value || TypedVariable.create_or_validate(value_type, on_change: on_change)
55
+ end
56
+
57
+ def []=(index, value)
58
+ index_var = TypedVariable.create_or_validate(:uint256, index, on_change: on_change)
59
+
60
+ raise "Sparse arrays are not supported" if index_var > data.size
61
+
62
+ old_value = self.data[index_var]
63
+ val_var = TypedVariable.create_or_validate(value_type, value, on_change: on_change)
64
+
65
+ if old_value != val_var
66
+ on_change&.call
67
+ self.data[index_var] ||= val_var
68
+ self.data[index_var].value = val_var.value
69
+ end
70
+ end
71
+
72
+ def push(value)
73
+ next_index = data.size
74
+
75
+ self.[]=(next_index, value)
76
+ nil
77
+ end
78
+
79
+ def pop
80
+ on_change&.call
81
+
82
+ data.pop
83
+ end
84
+
85
+ def length
86
+ data.length
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ module AttrPublicReadPrivateWrite
2
+ def attr_public_read_private_write(*names)
3
+ attr_accessor(*names)
4
+
5
+ names.each do |name|
6
+ private "#{name}="
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ module ContractErrors
2
+ class ContractError < StandardError
3
+ attr_accessor :contract
4
+ attr_accessor :error_status
5
+
6
+ def initialize(message, contract = nil)
7
+ super(message)
8
+ @contract = contract
9
+ end
10
+
11
+ def message
12
+ return super if contract.blank?
13
+
14
+ trace = !Rails.env.production? ? backtrace.join("\n") : ''
15
+
16
+ "#{contract.class.name} error: " + super
17
+ end
18
+ end
19
+
20
+ class StaticCallError < StandardError; end
21
+ class TransactionError < StandardError; end
22
+ class ContractRuntimeError < ContractError; end
23
+ class ContractDefinitionError < ContractError; end
24
+ class StateVariableTypeError < StandardError; end
25
+ class VariableTypeError < StandardError; end
26
+ class StateVariableMutabilityError < StandardError; end
27
+ class ContractArgumentError < StandardError; end
28
+ class CallingNonExistentContractError < TransactionError; end
29
+ class InvalidOverrideError < StandardError; end
30
+ class FunctionAlreadyDefinedError < StandardError; end
31
+ class InvalidEthscriptionError < StandardError; end
32
+ class InvalidDestructuringError < StandardError; end
33
+ class InvalidStateVariableChange < StandardError; end
34
+ end
@@ -0,0 +1,64 @@
1
+ class ContractType < TypedVariable
2
+ def initialize(...)
3
+ super(...)
4
+ end
5
+
6
+ def serialize
7
+ value.address
8
+ end
9
+
10
+ def method_missing(name, *args, **kwargs, &block)
11
+ value.send(name, *args, **kwargs, &block)
12
+ end
13
+
14
+ def respond_to_missing?(name, include_private = false)
15
+ value.respond_to?(name, include_private) || super
16
+ end
17
+
18
+ class Proxy
19
+ include ContractErrors
20
+ extend AttrPublicReadPrivateWrite
21
+
22
+ attr_public_read_private_write :contract_type, :address,
23
+ :uncast_address, :contract_interface
24
+
25
+ def ==(other)
26
+ return false unless other.is_a?(self.class)
27
+
28
+ other.contract_type == contract_type &&
29
+ other.address == address
30
+ end
31
+
32
+ def initialize(contract_type:, address:, contract_interface:)
33
+ self.uncast_address = address
34
+ address = TypedVariable.create_or_validate(:address, address).value
35
+
36
+ self.contract_type = contract_type
37
+ self.address = address
38
+ self.contract_interface = contract_interface
39
+ end
40
+
41
+ def method_missing(name, *args, **kwargs, &block)
42
+ computed_args = args.presence || kwargs
43
+
44
+ super unless contract_interface
45
+
46
+ known_function = contract_interface.public_abi[name]
47
+
48
+ unless known_function && known_function.args.length == computed_args.length
49
+ raise ContractError.new("Contract doesn't implement interface: #{contract_type}, #{name}")
50
+ end
51
+
52
+ TransactionContext.call_stack.execute_in_new_frame(
53
+ to_contract_address: address,
54
+ function: name,
55
+ args: computed_args,
56
+ type: :call
57
+ )
58
+ end
59
+
60
+ def respond_to_missing?(name, include_private = false)
61
+ !!contract_interface.public_abi[name] || super
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,102 @@
1
+ class MappingType < TypedVariable
2
+ def initialize(...)
3
+ super(...)
4
+ value.on_change = on_change
5
+ end
6
+
7
+ def serialize
8
+ value.serialize
9
+ end
10
+
11
+ class Proxy
12
+ extend AttrPublicReadPrivateWrite
13
+
14
+ attr_accessor :on_change
15
+ attr_public_read_private_write :transformed_keys, :data, :key_type, :value_type
16
+
17
+ def serialize
18
+ serialized_dirty_data = {}
19
+
20
+ transformed_keys.each do |key|
21
+ value = data[key]
22
+
23
+ unless value.value == value.type.default_value
24
+ serialized_dirty_data[key.serialize.to_s] = value.serialize
25
+ end
26
+ end
27
+
28
+ clean_data = data.except(*transformed_keys)
29
+ clean_data.merge(serialized_dirty_data).deep_dup
30
+ end
31
+
32
+ def ==(other)
33
+ return false unless other.is_a?(self.class)
34
+
35
+ other.key_type == key_type &&
36
+ other.value_type == value_type &&
37
+ other.serialize == serialize
38
+ end
39
+
40
+ def initialize(initial_value = {}, key_type:, value_type:, on_change: nil)
41
+ self.key_type = key_type
42
+ self.value_type = value_type
43
+
44
+ self.data = initial_value
45
+ self.transformed_keys = Set.new
46
+ self.on_change = on_change
47
+ end
48
+
49
+ def [](key_var)
50
+ raw_key = key_var.is_a?(TypedVariable) ? key_var.value : key_var
51
+ string_key = raw_key.to_s
52
+
53
+ typed_key_var = TypedVariable.create_or_validate(key_type, key_var, on_change: on_change)
54
+
55
+ # First, attempt a lookup using the typed key
56
+ value = data[typed_key_var]
57
+
58
+ # If no value is found, try looking it up as a string (how it would be stored in JSONB)
59
+ if value.nil? && data.key?(string_key)
60
+ value = TypedVariable.create_or_validate(value_type, data[string_key], on_change: on_change)
61
+
62
+ data.delete(string_key)
63
+ set_value(typed_key_var, value)
64
+ end
65
+
66
+ # If the value is still nil, it truly doesn't exist; create a new default value
67
+ if value.nil?
68
+ value = TypedVariable.create_or_validate(value_type, on_change: on_change)
69
+ set_value(typed_key_var, value)
70
+ end
71
+
72
+ value
73
+ end
74
+
75
+ def []=(key_var, value)
76
+ key_var = TypedVariable.create_or_validate(key_type, key_var, on_change: on_change)
77
+ val_var = TypedVariable.create_or_validate(value_type, value, on_change: on_change)
78
+
79
+ if value_type.mapping?
80
+ raise TypeError, "Mappings cannot be assigned to mappings"
81
+ end
82
+
83
+ old_value = self.data[key_var]
84
+
85
+ if old_value != val_var
86
+ on_change&.call
87
+
88
+ transformed_keys.add(key_var)
89
+
90
+ data[key_var] ||= val_var
91
+ data[key_var].value = val_var.value
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def set_value(key, value)
98
+ data[key] = value
99
+ transformed_keys.add(key)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,290 @@
1
+ class Type
2
+ include ContractErrors
3
+
4
+ attr_accessor :name, :metadata, :key_type, :value_type, :initial_length
5
+
6
+ INTEGER_TYPES = (8..256).step(8).flat_map do |num|
7
+ ["uint#{num}", "int#{num}"]
8
+ end.map(&:to_sym)
9
+
10
+ TYPES = [:string, :mapping, :address, :bytes32, :contract,
11
+ :bool, :address, :uint256, :int256, :array, :datetime, :bytes] + INTEGER_TYPES
12
+
13
+ TYPES.each do |type|
14
+ define_method("#{type}?") do
15
+ self.name == type
16
+ end
17
+ end
18
+
19
+ def self.value_types
20
+ TYPES.select do |type|
21
+ create(type).is_value_type?
22
+ end
23
+ end
24
+
25
+ def initialize(type_name, metadata = {})
26
+ if type_name.is_a?(Array)
27
+ if type_name.length != 1
28
+ raise "Invalid array type #{type_name.inspect}"
29
+ end
30
+
31
+ value_type = type_name.first
32
+
33
+ if TYPES.exclude?(value_type)
34
+ raise "Invalid type #{value_type.inspect}"
35
+ end
36
+
37
+ metadata = { value_type: value_type }
38
+ type_name = :array
39
+ end
40
+
41
+ type_name = type_name.to_sym
42
+
43
+ if TYPES.exclude?(type_name)
44
+ raise "Invalid type #{type_name}"
45
+ end
46
+
47
+ self.name = type_name.to_sym
48
+ self.metadata = metadata.deep_dup
49
+ end
50
+
51
+ def self.create(type_or_name, metadata = {})
52
+ return type_or_name if type_or_name.is_a?(self)
53
+
54
+ new(type_or_name, metadata)
55
+ end
56
+
57
+ def key_type=(type)
58
+ return if type.nil?
59
+ @key_type = self.class.create(type)
60
+ end
61
+
62
+ def value_type=(type)
63
+ return if type.nil?
64
+ @value_type = self.class.create(type)
65
+ end
66
+
67
+ def metadata=(metadata)
68
+ self.key_type = metadata[:key_type]
69
+ self.value_type = metadata[:value_type]
70
+ self.initial_length = metadata[:initial_length] if metadata[:initial_length]
71
+ end
72
+
73
+ def can_be_assigned_from?(other_type)
74
+ return true if self == other_type
75
+
76
+ if is_uint? && other_type.is_uint? || is_int? && other_type.is_int?
77
+ return extract_integer_bits >= other_type.extract_integer_bits
78
+ end
79
+
80
+ if address? && other_type.contract?
81
+ return true
82
+ end
83
+
84
+ false
85
+ end
86
+
87
+ def values_can_be_compared?(other_type)
88
+ return true if can_be_assigned_from?(other_type)
89
+
90
+ if is_uint? && other_type.is_uint? || is_int? && other_type.is_int?
91
+ return true
92
+ end
93
+ false
94
+ end
95
+
96
+ def metadata
97
+ (@metadata ||= {}).with_indifferent_access
98
+ end
99
+
100
+ def to_s
101
+ name.to_s
102
+ end
103
+
104
+ def default_value
105
+ is_int256_uint256_datetime = is_int? || is_uint? || datetime?
106
+
107
+ val = case
108
+ when is_int256_uint256_datetime
109
+ 0
110
+ when address?
111
+ "0x" + "0" * 40
112
+ when bytes32?
113
+ "0x" + "0" * 64
114
+ when string? || bytes?
115
+ ''
116
+ when bool?
117
+ false
118
+ when mapping?
119
+ MappingType::Proxy.new(key_type: key_type, value_type: value_type)
120
+ when array?
121
+ ArrayType::Proxy.new(value_type: value_type, initial_length: initial_length)
122
+ when contract?
123
+ ContractType::Proxy.new(contract_interface: metadata[:interface], address: nil, contract_type: nil)
124
+ else
125
+ raise "Unknown default value for #{self.inspect}"
126
+ end
127
+
128
+ check_and_normalize_literal(val)
129
+ end
130
+
131
+ def raise_variable_type_error(literal)
132
+ raise VariableTypeError.new("Invalid #{self}: #{literal.inspect}")
133
+ end
134
+
135
+ def parse_integer(literal)
136
+ base = literal.start_with?("0x") ? 16 : 10
137
+
138
+ begin
139
+ Integer(literal, base)
140
+ rescue ArgumentError => e
141
+ raise_variable_type_error(literal)
142
+ end
143
+ end
144
+
145
+ def check_and_normalize_literal(literal)
146
+ if literal.is_a?(TypedVariable)
147
+ raise VariableTypeError, "Only literals can be passed to check_and_normalize_literal: #{literal.inspect}"
148
+ end
149
+
150
+ if address?
151
+ if literal.is_a?(ContractType::Proxy)
152
+ return literal.address
153
+ end
154
+
155
+ unless literal.is_a?(String) && literal.match?(/\A0x[a-f0-9]{40}\z/i)
156
+ raise_variable_type_error(literal)
157
+ end
158
+
159
+ return literal.downcase
160
+ elsif is_uint?
161
+ if literal.is_a?(String)
162
+ literal = parse_integer(literal)
163
+ end
164
+
165
+ if literal.is_a?(Integer) && literal.between?(0, 2 ** extract_integer_bits - 1)
166
+ return literal
167
+ end
168
+
169
+ raise_variable_type_error(literal)
170
+ elsif is_int?
171
+ if literal.is_a?(String)
172
+ literal = parse_integer(literal)
173
+ end
174
+
175
+ if literal.is_a?(Integer) && literal.between?(-2 ** (extract_integer_bits - 1), 2 ** (extract_integer_bits - 1) - 1)
176
+ return literal
177
+ end
178
+
179
+ raise_variable_type_error(literal)
180
+ elsif string?
181
+ unless literal.is_a?(String)
182
+ raise_variable_type_error(literal)
183
+ end
184
+
185
+ return literal.freeze
186
+ elsif bool?
187
+ unless literal == true || literal == false
188
+ raise_variable_type_error(literal)
189
+ end
190
+
191
+ return literal
192
+ elsif bytes32?
193
+ unless literal.is_a?(String) && literal.match?(/\A0x[a-f0-9]{64}\z/i)
194
+ raise_variable_type_error(literal)
195
+ end
196
+
197
+ return literal.downcase
198
+ elsif bytes?
199
+ if literal.is_a?(String) && literal.length == 0
200
+ return literal
201
+ end
202
+
203
+ unless literal.is_a?(String) && literal.match?(/\A0x[a-fA-F0-9]*\z/) && literal.size.even?
204
+ raise_variable_type_error(literal)
205
+ end
206
+
207
+ return literal.downcase
208
+ elsif datetime?
209
+ dummy_uint = Type.create(:uint256)
210
+
211
+ begin
212
+ return dummy_uint.check_and_normalize_literal(literal)
213
+ rescue VariableTypeError => e
214
+ raise_variable_type_error(literal)
215
+ end
216
+ elsif mapping?
217
+ if literal.is_a?(MappingType::Proxy)
218
+ return literal
219
+ end
220
+
221
+ unless literal.is_a?(Hash)
222
+ raise VariableTypeError.new("invalid #{literal}")
223
+ end
224
+
225
+ proxy = MappingType::Proxy.new(literal, key_type: key_type, value_type: value_type)
226
+
227
+ return proxy
228
+ elsif array?
229
+ if literal.is_a?(ArrayType::Proxy)
230
+ return literal
231
+ end
232
+
233
+ unless literal.is_a?(Array)
234
+ raise_variable_type_error(literal)
235
+ end
236
+
237
+ data = literal.map do |value|
238
+ TypedVariable.create(value_type, value)
239
+ end
240
+
241
+ proxy = ArrayType::Proxy.new(data, value_type: value_type, initial_length: initial_length)
242
+
243
+ return proxy
244
+ elsif contract?
245
+ if literal.is_a?(ContractType::Proxy)
246
+ return literal
247
+ else
248
+ raise_variable_type_error("No literals allowed for contract types")
249
+ end
250
+ end
251
+
252
+ raise VariableTypeError.new("Unknown type #{self.inspect}: #{literal.inspect}")
253
+ end
254
+
255
+ def is_uint?
256
+ name.to_s.start_with?('uint')
257
+ end
258
+
259
+ def is_int?
260
+ name.to_s.start_with?('int')
261
+ end
262
+
263
+ def extract_integer_bits
264
+ return name.to_s[4..-1].to_i if is_uint?
265
+ return name.to_s[3..-1].to_i if is_int?
266
+ raise "Not an integer type: #{self}"
267
+ end
268
+
269
+ def ==(other)
270
+ other.is_a?(self.class) &&
271
+ other.name == name &&
272
+ other.metadata.except(:initial_length) == metadata.except(:initial_length)
273
+ end
274
+
275
+ def !=(other)
276
+ !(self == other)
277
+ end
278
+
279
+ def hash
280
+ [name, metadata].hash
281
+ end
282
+
283
+ def eql?(other)
284
+ hash == other.hash
285
+ end
286
+
287
+ def is_value_type?
288
+ !mapping? && !array?
289
+ end
290
+ end
@@ -0,0 +1,129 @@
1
+ class TypedVariable
2
+ include ContractErrors
3
+ extend AttrPublicReadPrivateWrite
4
+
5
+ attr_accessor :value, :on_change
6
+ attr_public_read_private_write :type
7
+
8
+ def initialize(type, value = nil, on_change: nil, **options)
9
+ self.type = type
10
+ self.value = value || type.default_value
11
+ self.on_change = on_change
12
+ end
13
+
14
+ def self.create(type, value = nil, on_change: nil, **options)
15
+ type = Type.create(type)
16
+
17
+ options[:on_change] = on_change
18
+
19
+ if type.mapping?
20
+ MappingType.new(type, value, **options)
21
+ elsif type.array?
22
+ ArrayType.new(type, value, **options)
23
+ elsif type.contract?
24
+ ContractType.new(type, value, **options)
25
+ else
26
+ new(type, value, **options)
27
+ end
28
+ end
29
+
30
+ def self.create_or_validate(type, value = nil, on_change: nil)
31
+ if value.is_a?(TypedVariable)
32
+ unless Type.create(type).can_be_assigned_from?(value.type)
33
+ raise VariableTypeError.new("invalid #{type}: #{value.inspect}")
34
+ end
35
+
36
+ value = value.value
37
+ end
38
+
39
+ create(type, value, on_change: on_change)
40
+ end
41
+
42
+ def as_json(args = {})
43
+ serialize
44
+ end
45
+
46
+ def serialize
47
+ value
48
+ end
49
+
50
+ def to_s
51
+ if value.is_a?(String) || value.is_a?(Integer)
52
+ value.to_s
53
+ else
54
+ raise "No string conversion"
55
+ end
56
+ end
57
+
58
+ def deserialize(serialized_value)
59
+ self.value = serialized_value
60
+ end
61
+
62
+ def value=(new_value)
63
+ new_value = type.check_and_normalize_literal(new_value)
64
+
65
+ if @value != new_value
66
+ on_change&.call
67
+
68
+ if new_value.respond_to?(:on_change=)
69
+ new_value.on_change = on_change
70
+ end
71
+
72
+ @value = new_value
73
+ end
74
+ end
75
+
76
+ def method_missing(name, *args, &block)
77
+ if value.respond_to?(name)
78
+ result = value.send(name, *args, &block)
79
+
80
+ if result.class == value.class
81
+ begin
82
+ result = type.check_and_normalize_literal(result)
83
+ rescue ContractErrors::VariableTypeError => e
84
+ if type.is_uint?
85
+ result = TypedVariable.create(:uint256, result)
86
+ else
87
+ raise
88
+ end
89
+ end
90
+ end
91
+
92
+ result
93
+
94
+ if name.to_s.end_with?("=") && !%w[>= <=].include?(name.to_s[-2..])
95
+ self.value = result if type.is_value_type?
96
+ self
97
+ else
98
+ result
99
+ end
100
+ else
101
+ super
102
+ end
103
+ end
104
+
105
+ def respond_to_missing?(name, include_private = false)
106
+ value.respond_to?(name, include_private) || super
107
+ end
108
+
109
+ def !=(other)
110
+ !(self == other)
111
+ end
112
+
113
+ def ==(other)
114
+ if other.is_a?(self.class)
115
+ return false unless type.values_can_be_compared?(other.type)
116
+ return value == other.value
117
+ else
118
+ return value == TypedVariable.create(type, other).value
119
+ end
120
+ end
121
+
122
+ def hash
123
+ [value, type].hash
124
+ end
125
+
126
+ def eql?(other)
127
+ hash == other.hash
128
+ end
129
+ end
@@ -0,0 +1,16 @@
1
+
2
+
3
+ require 'active_support/all'
4
+
5
+
6
+ ## our own code
7
+ require_relative 'typed/contract_errors' ## move upstream to 0xfacet !!!
8
+
9
+ require_relative 'typed/attr_public_read_private_write'
10
+ require_relative 'typed/type'
11
+ require_relative 'typed/typed_variable'
12
+ require_relative 'typed/array_type'
13
+ require_relative 'typed/mapping_type'
14
+ require_relative 'typed/contract_type'
15
+
16
+
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: 0xfacet-typed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7'
33
+ - !ruby/object:Gem::Dependency
34
+ name: hoe
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4.0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '4.0'
47
+ description: 0xfacet-typed - solidity-like value and reference types for rubidity
48
+ o.g.
49
+ email: gerald.bauer@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - CHANGELOG.md
54
+ - Manifest.txt
55
+ - README.md
56
+ files:
57
+ - CHANGELOG.md
58
+ - Manifest.txt
59
+ - README.md
60
+ - Rakefile
61
+ - lib/0xfacet/typed.rb
62
+ - lib/0xfacet/typed/array_type.rb
63
+ - lib/0xfacet/typed/attr_public_read_private_write.rb
64
+ - lib/0xfacet/typed/contract_errors.rb
65
+ - lib/0xfacet/typed/contract_type.rb
66
+ - lib/0xfacet/typed/mapping_type.rb
67
+ - lib/0xfacet/typed/type.rb
68
+ - lib/0xfacet/typed/typed_variable.rb
69
+ homepage: https://github.com/s6ruby/rubidity.review
70
+ licenses:
71
+ - Public Domain
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options:
75
+ - "--main"
76
+ - README.md
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '2.3'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.4.10
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: 0xfacet-typed - solidity-like value and reference types for rubidity o.g.
94
+ test_files: []