crystalruby 0.2.3 → 0.3.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 +4 -4
- data/CHANGELOG.md +2 -0
- data/Dockerfile +23 -2
- data/README.md +395 -198
- data/Rakefile +4 -3
- data/crystalruby.gemspec +2 -2
- data/examples/adder/adder.rb +1 -1
- data/exe/crystalruby +1 -0
- data/lib/crystalruby/adapter.rb +143 -73
- data/lib/crystalruby/arc_mutex.rb +47 -0
- data/lib/crystalruby/compilation.rb +32 -3
- data/lib/crystalruby/config.rb +41 -37
- data/lib/crystalruby/function.rb +216 -73
- data/lib/crystalruby/library.rb +157 -51
- data/lib/crystalruby/reactor.rb +63 -44
- data/lib/crystalruby/source_reader.rb +92 -0
- data/lib/crystalruby/template.rb +16 -5
- data/lib/crystalruby/templates/function.cr +11 -10
- data/lib/crystalruby/templates/index.cr +53 -66
- data/lib/crystalruby/templates/inline_chunk.cr +1 -1
- data/lib/crystalruby/templates/ruby_interface.cr +34 -0
- data/lib/crystalruby/templates/top_level_function.cr +62 -0
- data/lib/crystalruby/templates/top_level_ruby_interface.cr +33 -0
- data/lib/crystalruby/typebuilder.rb +11 -55
- data/lib/crystalruby/typemaps.rb +92 -67
- data/lib/crystalruby/types/concerns/allocator.rb +80 -0
- data/lib/crystalruby/types/fixed_width/named_tuple.cr +80 -0
- data/lib/crystalruby/types/fixed_width/named_tuple.rb +86 -0
- data/lib/crystalruby/types/fixed_width/proc.cr +45 -0
- data/lib/crystalruby/types/fixed_width/proc.rb +79 -0
- data/lib/crystalruby/types/fixed_width/tagged_union.cr +53 -0
- data/lib/crystalruby/types/fixed_width/tagged_union.rb +113 -0
- data/lib/crystalruby/types/fixed_width/tuple.cr +82 -0
- data/lib/crystalruby/types/fixed_width/tuple.rb +92 -0
- data/lib/crystalruby/types/fixed_width.cr +138 -0
- data/lib/crystalruby/types/fixed_width.rb +205 -0
- data/lib/crystalruby/types/primitive.cr +21 -0
- data/lib/crystalruby/types/primitive.rb +117 -0
- data/lib/crystalruby/types/primitive_types/bool.cr +34 -0
- data/lib/crystalruby/types/primitive_types/bool.rb +11 -0
- data/lib/crystalruby/types/primitive_types/nil.cr +35 -0
- data/lib/crystalruby/types/primitive_types/nil.rb +16 -0
- data/lib/crystalruby/types/primitive_types/numbers.cr +37 -0
- data/lib/crystalruby/types/primitive_types/numbers.rb +28 -0
- data/lib/crystalruby/types/primitive_types/symbol.cr +55 -0
- data/lib/crystalruby/types/primitive_types/symbol.rb +35 -0
- data/lib/crystalruby/types/primitive_types/time.cr +35 -0
- data/lib/crystalruby/types/primitive_types/time.rb +25 -0
- data/lib/crystalruby/types/type.cr +64 -0
- data/lib/crystalruby/types/type.rb +249 -30
- data/lib/crystalruby/types/variable_width/array.cr +74 -0
- data/lib/crystalruby/types/variable_width/array.rb +88 -0
- data/lib/crystalruby/types/variable_width/hash.cr +146 -0
- data/lib/crystalruby/types/variable_width/hash.rb +117 -0
- data/lib/crystalruby/types/variable_width/string.cr +36 -0
- data/lib/crystalruby/types/variable_width/string.rb +18 -0
- data/lib/crystalruby/types/variable_width.cr +23 -0
- data/lib/crystalruby/types/variable_width.rb +46 -0
- data/lib/crystalruby/types.rb +32 -13
- data/lib/crystalruby/version.rb +2 -2
- data/lib/crystalruby.rb +13 -6
- metadata +42 -22
- data/lib/crystalruby/types/array.rb +0 -15
- data/lib/crystalruby/types/bool.rb +0 -3
- data/lib/crystalruby/types/hash.rb +0 -17
- data/lib/crystalruby/types/named_tuple.rb +0 -28
- data/lib/crystalruby/types/nil.rb +0 -3
- data/lib/crystalruby/types/numbers.rb +0 -5
- data/lib/crystalruby/types/string.rb +0 -3
- data/lib/crystalruby/types/symbol.rb +0 -3
- data/lib/crystalruby/types/time.rb +0 -8
- data/lib/crystalruby/types/tuple.rb +0 -17
- data/lib/crystalruby/types/type_serializer/json.rb +0 -41
- data/lib/crystalruby/types/type_serializer.rb +0 -37
- data/lib/crystalruby/types/typedef.rb +0 -57
- data/lib/crystalruby/types/union_type.rb +0 -43
- data/lib/module.rb +0 -3
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CrystalRuby::Types
|
4
|
+
Array = VariableWidth.build(error: "Array type must have a type parameter. E.g. Array(Float64)")
|
5
|
+
|
6
|
+
# An array-like, reference counted manually managed memory type.
|
7
|
+
# Shareable between Crystal and Crystal.
|
8
|
+
def self.Array(type)
|
9
|
+
VariableWidth.build(:Array, inner_types: [type], convert_if: [Array, Root::Array], superclass: Array) do
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
# Implement the Enumerable interface
|
13
|
+
# Helps this object to act like an Array
|
14
|
+
def each
|
15
|
+
size.times { |i| yield self[i] }
|
16
|
+
end
|
17
|
+
|
18
|
+
# We only accept Array-like values, from which all elements
|
19
|
+
# can successfully be cast to our inner type
|
20
|
+
def self.cast!(value)
|
21
|
+
unless value.is_a?(Array) || value.is_a?(Root::Array) && value.all?(&inner_type.method(:valid_cast?))
|
22
|
+
raise CrystalRuby::InvalidCastError, "Cannot cast #{value} to #{inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
if inner_type.primitive?
|
26
|
+
value.map(&inner_type.method(:to_ffi_repr))
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.copy_to!(rbval, memory:)
|
33
|
+
data_pointer = malloc(rbval.size * inner_type.refsize)
|
34
|
+
|
35
|
+
memory[size_offset].write_uint32(rbval.size)
|
36
|
+
memory[data_offset].write_pointer(data_pointer)
|
37
|
+
|
38
|
+
if inner_type.primitive?
|
39
|
+
data_pointer.send("put_array_of_#{inner_type.ffi_type}", 0, rbval)
|
40
|
+
else
|
41
|
+
rbval.each_with_index do |val, i|
|
42
|
+
inner_type.write_single(data_pointer[i * refsize], val)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.each_child_address(pointer)
|
48
|
+
size = pointer[size_offset].get_int32(0)
|
49
|
+
pointer = pointer[data_offset].read_pointer
|
50
|
+
size.times do |i|
|
51
|
+
yield inner_type, pointer[i * inner_type.refsize]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def checked_offset!(index, size)
|
56
|
+
raise "Index out of bounds: #{index} >= #{size}" if index >= size
|
57
|
+
|
58
|
+
if index < 0
|
59
|
+
raise "Index out of bounds: #{index} < -#{size}" if index < -size
|
60
|
+
|
61
|
+
index += size
|
62
|
+
end
|
63
|
+
index
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return the element at the given index.
|
67
|
+
# This will automatically increment
|
68
|
+
# the reference count if not a primitive type.
|
69
|
+
def [](index)
|
70
|
+
inner_type.fetch_single(data_pointer[checked_offset!(index, size) * inner_type.refsize])
|
71
|
+
end
|
72
|
+
|
73
|
+
# Overwrite the element at the given index
|
74
|
+
# The replaced element will have
|
75
|
+
# its reference count decremented.
|
76
|
+
def []=(index, value)
|
77
|
+
inner_type.write_single(data_pointer[checked_offset!(index, size) * inner_type.refsize], value)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Load values stored inside array type.
|
81
|
+
# If it's a primitive type, we can quickly bulk load the values.
|
82
|
+
# Otherwise we need toinstantiate new ref-checked instances.
|
83
|
+
def value(native: false)
|
84
|
+
inner_type.fetch_multi(data_pointer, size, native: native)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
class <%= base_crystal_class_name %> < CrystalRuby::Types::VariableWidth
|
2
|
+
|
3
|
+
def initialize(hash : Hash(<%= key_type.native_type_expr %>, <%= value_type.native_type_expr %>))
|
4
|
+
@memory = malloc(data_offset + 8)
|
5
|
+
self.value = hash
|
6
|
+
increment_ref_count!
|
7
|
+
end
|
8
|
+
|
9
|
+
def value=(hash : Hash(<%= key_type.native_type_expr %>, <%= value_type.native_type_expr %>))
|
10
|
+
if self.ref_count > 0
|
11
|
+
self.class.decr_inner_ref_counts!(memory)
|
12
|
+
end
|
13
|
+
self.class.copy_to!(hash, self.memory)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other : <%= native_type_expr %>)
|
17
|
+
native == other
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.copy_to!(hash : Hash(<%= key_type.native_type_expr %>, <%= value_type.native_type_expr %>), memory : Pointer(::UInt8))
|
21
|
+
data_pointer = malloc(hash.size * (keysize + valsize)).as(Pointer(::UInt8))
|
22
|
+
|
23
|
+
hash.keys.each_with_index do |key, i|
|
24
|
+
<%= key_type.crystal_class_name %>.write_single(data_pointer + i * keysize, key)
|
25
|
+
end
|
26
|
+
|
27
|
+
hash.values.each_with_index do |value, i|
|
28
|
+
<%= value_type.crystal_class_name %>.write_single(data_pointer + hash.size * keysize + i * valsize, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
(memory+size_offset).as(Pointer(::UInt32)).value = hash.size.to_u32
|
32
|
+
(memory+data_offset).as(Pointer(::UInt64)).value = data_pointer.address
|
33
|
+
end
|
34
|
+
|
35
|
+
def value
|
36
|
+
::Hash.zip(keys, values)
|
37
|
+
end
|
38
|
+
|
39
|
+
def native : ::Hash(<%= key_type.native_type_expr %>, <%= value_type.native_type_expr %>)
|
40
|
+
::Hash.zip(keys_native, values_native)
|
41
|
+
end
|
42
|
+
|
43
|
+
include Enumerable(::Tuple(<%= key_type.native_type_expr %>, <%= value_type.native_type_expr %>))
|
44
|
+
|
45
|
+
def each
|
46
|
+
size.times do |i|
|
47
|
+
yield({keys_native[i], values_native[i]})
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def size
|
52
|
+
(memory+size_offset).as(Pointer(::UInt32)).value.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.keysize
|
56
|
+
<%= key_type.refsize %>
|
57
|
+
end
|
58
|
+
|
59
|
+
def keysize
|
60
|
+
<%= key_type.refsize %>
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.valsize
|
64
|
+
<%= value_type.refsize %>
|
65
|
+
end
|
66
|
+
|
67
|
+
def valsize
|
68
|
+
<%= value_type.refsize %>
|
69
|
+
end
|
70
|
+
|
71
|
+
def []=(key : <%= key_type.native_type_expr %>, value : <%= value_type.native_type_expr %>)
|
72
|
+
index = index_of(key)
|
73
|
+
if index
|
74
|
+
<%= value_type.crystal_class_name %>.write_single(data_pointer + size * keysize + index * valsize, value)
|
75
|
+
else
|
76
|
+
self.value = self.native.merge({key => value})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def key_ptr : Pointer(<%= !key_type.numeric? ? "UInt64" : key_type.native_type_expr %>)
|
81
|
+
data_pointer.as(Pointer(<%= !key_type.numeric? ? "UInt8" : key_type.native_type_expr %>))
|
82
|
+
end
|
83
|
+
|
84
|
+
def value_ptr : Pointer(<%= !value_type.numeric? ? "UInt64" : value_type.native_type_expr %>)
|
85
|
+
(data_pointer + size * keysize).as(Pointer(<%= !value_type.numeric? ? "UInt8" : value_type.native_type_expr %>))
|
86
|
+
end
|
87
|
+
|
88
|
+
def []?(key : <%= key_type.native_type_expr %>)
|
89
|
+
index = index_of(key)
|
90
|
+
if index
|
91
|
+
values[index]
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def [](key : <%= key_type.native_type_expr %>)
|
98
|
+
index = index_of(key)
|
99
|
+
if index
|
100
|
+
values[index]
|
101
|
+
else
|
102
|
+
raise "Key not found"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def data_pointer
|
108
|
+
Pointer(::UInt8).new((@memory + data_offset).as(::Pointer(UInt64)).value)
|
109
|
+
end
|
110
|
+
|
111
|
+
def keys
|
112
|
+
keys = [] of <%= key_type.numeric? ? key_type.native_type_expr : key_type.crystal_class_name %>
|
113
|
+
size.times do |i|
|
114
|
+
keys << <%= !key_type.numeric? ? "#{key_type.crystal_class_name}.fetch_single(data_pointer + i * keysize)" : "key_ptr[i]" %>
|
115
|
+
end
|
116
|
+
keys
|
117
|
+
end
|
118
|
+
|
119
|
+
def values
|
120
|
+
values = [] of <%= value_type.numeric? ? value_type.native_type_expr : value_type.crystal_class_name %>
|
121
|
+
size.times do |i|
|
122
|
+
values << <%= !value_type.numeric? ? "#{value_type.crystal_class_name}.fetch_single(data_pointer + size * keysize + i * valsize)" : "value_ptr[i]" %>
|
123
|
+
end
|
124
|
+
values
|
125
|
+
end
|
126
|
+
|
127
|
+
def keys_native
|
128
|
+
keys = [] of <%= key_type.native_type_expr %>
|
129
|
+
size.times do |i|
|
130
|
+
keys << <%= !key_type.numeric? ? "#{key_type.crystal_class_name}.fetch_single(data_pointer + i * keysize).native" : "key_ptr[i]" %>.as(<%= key_type.native_type_expr %>)
|
131
|
+
end
|
132
|
+
keys
|
133
|
+
end
|
134
|
+
|
135
|
+
def values_native
|
136
|
+
values = [] of <%= value_type.native_type_expr %>
|
137
|
+
size.times do |i|
|
138
|
+
values << <%= !value_type.numeric? ? "#{value_type.crystal_class_name}.fetch_single(data_pointer + size * keysize + i * valsize).native" : "value_ptr[i]" %>.as(<%= value_type.native_type_expr %>)
|
139
|
+
end
|
140
|
+
values
|
141
|
+
end
|
142
|
+
|
143
|
+
def index_of(key : <%= key_type.native_type_expr %>)
|
144
|
+
keys.index(key)
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CrystalRuby::Types
|
4
|
+
Hash = VariableWidth.build(error: "Hash type must have 2 type parameters. E.g. Hash(Float64, String)")
|
5
|
+
|
6
|
+
def self.Hash(key_type, value_type)
|
7
|
+
VariableWidth.build(:Hash, inner_types: [key_type, value_type], convert_if: [Root::Hash], superclass: Hash) do
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
def_delegators :@class, :value_type, :key_type
|
11
|
+
|
12
|
+
# Implement the Enumerable interface
|
13
|
+
# Helps this object to act like a true Hash
|
14
|
+
def each
|
15
|
+
if block_given?
|
16
|
+
size.times { |i| yield key_for_index(i), value_for_index(i) }
|
17
|
+
else
|
18
|
+
to_enum(:each)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def keys
|
23
|
+
each.map { |k, _| k }
|
24
|
+
end
|
25
|
+
|
26
|
+
def values
|
27
|
+
each.map { |_, v| v }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.key_type
|
31
|
+
inner_types.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.value_type
|
35
|
+
inner_types.last
|
36
|
+
end
|
37
|
+
|
38
|
+
# We only accept Hash-like values, from which all elements
|
39
|
+
# can successfully be cast to our inner types
|
40
|
+
def self.cast!(value)
|
41
|
+
unless (value.is_a?(Hash) || value.is_a?(Root::Hash)) && value.keys.all?(&key_type.method(:valid_cast?)) && value.values.all?(&value_type.method(:valid_cast?))
|
42
|
+
raise CrystalRuby::InvalidCastError, "Cannot cast #{value} to #{inspect}"
|
43
|
+
end
|
44
|
+
|
45
|
+
[[key_type, value.keys], [value_type, value.values]].map do |type, values|
|
46
|
+
if type.primitive?
|
47
|
+
values.map(&type.method(:to_ffi_repr))
|
48
|
+
else
|
49
|
+
values
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.copy_to!((keys, values), memory:)
|
55
|
+
data_pointer = malloc(values.size * (key_type.refsize + value_type.refsize))
|
56
|
+
|
57
|
+
memory[size_offset].write_uint32(values.size)
|
58
|
+
memory[data_offset].write_pointer(data_pointer)
|
59
|
+
|
60
|
+
[
|
61
|
+
[key_type, data_pointer, keys],
|
62
|
+
[value_type, data_pointer[values.length * key_type.refsize], values]
|
63
|
+
].each do |type, pointer, list|
|
64
|
+
if type.primitive?
|
65
|
+
pointer.send("put_array_of_#{type.ffi_type}", 0, list)
|
66
|
+
else
|
67
|
+
list.each_with_index do |val, i|
|
68
|
+
type.write_single(pointer[i * type.refsize], val)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def index_for_key(key)
|
75
|
+
size.times { |i| return i if key_for_index(i) == key }
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def key_for_index(index)
|
80
|
+
key_type.fetch_single(data_pointer[index * key_type.refsize])
|
81
|
+
end
|
82
|
+
|
83
|
+
def value_for_index(index)
|
84
|
+
value_type.fetch_single(data_pointer[key_type.refsize * size + index * value_type.refsize])
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.each_child_address(pointer)
|
88
|
+
size = pointer[size_offset].read_int32
|
89
|
+
pointer = pointer[data_offset].read_pointer
|
90
|
+
size.times do |i|
|
91
|
+
yield key_type, pointer[i * key_type.refsize]
|
92
|
+
yield value_type, pointer[size * key_type.refsize + i * value_type.refsize]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def [](key)
|
97
|
+
return nil unless index = index_for_key(key)
|
98
|
+
|
99
|
+
value_for_index(index)
|
100
|
+
end
|
101
|
+
|
102
|
+
def []=(key, value)
|
103
|
+
if index = index_for_key(key)
|
104
|
+
value_type.write_single(data_pointer[key_type.refsize * size + index * value_type.refsize], value)
|
105
|
+
else
|
106
|
+
method_missing(:[]=, key, value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def value(native: false)
|
111
|
+
keys = key_type.fetch_multi(data_pointer, size, native: native)
|
112
|
+
values = value_type.fetch_multi(data_pointer[key_type.refsize * size], size, native: native)
|
113
|
+
keys.zip(values).to_h
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class <%= base_crystal_class_name %> < CrystalRuby::Types::VariableWidth
|
2
|
+
|
3
|
+
def initialize(string : ::String)
|
4
|
+
@memory = malloc(data_offset + 8)
|
5
|
+
self.value = string
|
6
|
+
increment_ref_count!
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.copy_to!(value : ::String, memory : Pointer(::UInt8))
|
10
|
+
data_pointer = malloc(value.bytesize.to_u32).as(Pointer(::UInt8))
|
11
|
+
data_pointer.copy_from(value.to_unsafe, value.bytesize)
|
12
|
+
(memory+size_offset).as(Pointer(::UInt32)).value = value.bytesize.to_u32
|
13
|
+
(memory+data_offset).as(Pointer(::UInt64)).value = data_pointer.address
|
14
|
+
end
|
15
|
+
|
16
|
+
def value=(string : ::String)
|
17
|
+
if self.ref_count > 0
|
18
|
+
self.class.decr_inner_ref_counts!(memory)
|
19
|
+
end
|
20
|
+
self.class.copy_to!(string, self.memory)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other : <%= native_type_expr %>)
|
24
|
+
native == other
|
25
|
+
end
|
26
|
+
|
27
|
+
def value : ::String
|
28
|
+
char_ptr = (memory + data_offset).as(Pointer(Pointer(::UInt8)))
|
29
|
+
size = (memory + size_offset).as(Pointer(::UInt32))
|
30
|
+
::String.new(char_ptr[0], size[0])
|
31
|
+
end
|
32
|
+
|
33
|
+
def native : ::String
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CrystalRuby::Types
|
2
|
+
String = VariableWidth.build(:String, convert_if: [String, Root::String]) do
|
3
|
+
def self.cast!(rbval)
|
4
|
+
rbval.to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.copy_to!(rbval, memory:)
|
8
|
+
data_pointer = malloc(rbval.bytesize)
|
9
|
+
data_pointer.write_string(rbval)
|
10
|
+
memory[size_offset].write_uint32(rbval.size)
|
11
|
+
memory[data_offset].write_pointer(data_pointer)
|
12
|
+
end
|
13
|
+
|
14
|
+
def value(native: false)
|
15
|
+
data_pointer.read_string(size)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CrystalRuby
|
2
|
+
module Types
|
3
|
+
class VariableWidth < FixedWidth
|
4
|
+
|
5
|
+
def self.size_offset
|
6
|
+
4
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.data_offset
|
10
|
+
8
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.memsize
|
14
|
+
8
|
15
|
+
end
|
16
|
+
|
17
|
+
def variable_width?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CrystalRuby
|
2
|
+
module Types
|
3
|
+
# A variable with type operates much like a fixed width type, but
|
4
|
+
# it writes a size and a pointer to the type memory instead of the data itself.
|
5
|
+
# When we decrement our internal ref count we need to resolve the pointer.
|
6
|
+
# The layout is a tiny bit different (data begins at byte 8 to allow room for size uint32 at byte 4)
|
7
|
+
class VariableWidth < FixedWidth
|
8
|
+
def self.variable_width?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.crystal_supertype
|
13
|
+
"CrystalRuby::Types::VariableWidth"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build(
|
17
|
+
typename = nil,
|
18
|
+
error: nil,
|
19
|
+
inner_types: nil,
|
20
|
+
inner_keys: nil,
|
21
|
+
ffi_type: :pointer,
|
22
|
+
size_offset: 4,
|
23
|
+
data_offset: 8,
|
24
|
+
memsize: FFI.type_size(ffi_type),
|
25
|
+
refsize: 8,
|
26
|
+
convert_if: [],
|
27
|
+
superclass: VariableWidth,
|
28
|
+
&block
|
29
|
+
)
|
30
|
+
inner_types&.each(&Type.method(:validate!))
|
31
|
+
|
32
|
+
Class.new(superclass) do
|
33
|
+
bind_local_vars!(
|
34
|
+
%i[typename error inner_types inner_keys ffi_type memsize convert_if data_offset size_offset
|
35
|
+
refsize], binding
|
36
|
+
)
|
37
|
+
class_eval(&block) if block_given?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
require_relative "variable_width/string"
|
45
|
+
require_relative "variable_width/array"
|
46
|
+
require_relative "variable_width/hash"
|
data/lib/crystalruby/types.rb
CHANGED
@@ -1,18 +1,37 @@
|
|
1
|
-
require_relative "types/type"
|
2
|
-
require_relative "types/union_type"
|
3
|
-
require_relative "types/typedef"
|
4
|
-
require_relative "types/string"
|
5
|
-
require_relative "types/time"
|
6
|
-
require_relative "types/symbol"
|
7
|
-
require_relative "types/array"
|
8
|
-
require_relative "types/hash"
|
9
|
-
require_relative "types/nil"
|
10
|
-
require_relative "types/bool"
|
11
|
-
require_relative "types/named_tuple"
|
12
|
-
require_relative "types/tuple"
|
13
|
-
require_relative "types/numbers"
|
14
1
|
|
15
2
|
module CrystalRuby
|
16
3
|
module Types
|
4
|
+
# Store references to root types so that we can reference these in places where
|
5
|
+
# we load the CrystalRuby equivalents into the global namespace
|
6
|
+
module Root
|
7
|
+
Symbol = ::Symbol
|
8
|
+
String = ::String
|
9
|
+
Array = ::Array
|
10
|
+
Hash = ::Hash
|
11
|
+
Time = ::Time
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.const_missing(const_name)
|
15
|
+
return @fallback.const_get(const_name) if @fallback&.const_defined?(const_name)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.method_missing(method_name, *args)
|
20
|
+
return @fallback.send(method_name, *args) if @fallback&.method_defined?(method_name)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.with_binding_fallback(fallback)
|
25
|
+
@fallback, previous_fallback = fallback, @fallback
|
26
|
+
@fallback = @fallback.class unless @fallback.kind_of?(Module)
|
27
|
+
yield binding
|
28
|
+
ensure
|
29
|
+
@fallback = previous_fallback
|
30
|
+
end
|
17
31
|
end
|
18
32
|
end
|
33
|
+
require_relative "types/concerns/allocator"
|
34
|
+
require_relative "types/type"
|
35
|
+
require_relative "types/primitive"
|
36
|
+
require_relative "types/fixed_width"
|
37
|
+
require_relative "types/variable_width"
|
data/lib/crystalruby/version.rb
CHANGED
data/lib/crystalruby.rb
CHANGED
@@ -3,11 +3,12 @@
|
|
3
3
|
require "ffi"
|
4
4
|
require "digest"
|
5
5
|
require "fileutils"
|
6
|
-
require "
|
6
|
+
require "prism"
|
7
7
|
require "pathname"
|
8
8
|
|
9
9
|
require_relative "crystalruby/config"
|
10
10
|
require_relative "crystalruby/version"
|
11
|
+
require_relative "crystalruby/arc_mutex"
|
11
12
|
require_relative "crystalruby/typemaps"
|
12
13
|
require_relative "crystalruby/types"
|
13
14
|
require_relative "crystalruby/typebuilder"
|
@@ -17,7 +18,7 @@ require_relative "crystalruby/adapter"
|
|
17
18
|
require_relative "crystalruby/reactor"
|
18
19
|
require_relative "crystalruby/library"
|
19
20
|
require_relative "crystalruby/function"
|
20
|
-
require_relative "
|
21
|
+
require_relative "crystalruby/source_reader"
|
21
22
|
|
22
23
|
module CrystalRuby
|
23
24
|
module_function
|
@@ -37,19 +38,25 @@ module CrystalRuby
|
|
37
38
|
def check_crystal_ruby!
|
38
39
|
return if system("which crystal > /dev/null 2>&1")
|
39
40
|
|
40
|
-
|
41
|
-
"See https://crystal-lang.org/install
|
41
|
+
msg = "Crystal executable not found. Please ensure Crystal is installed and in your PATH. " \
|
42
|
+
"See https://crystal-lang.org/install/."
|
43
|
+
|
44
|
+
if config.crystal_missing_ignore
|
45
|
+
config.logger.error msg
|
46
|
+
else
|
47
|
+
raise msg
|
48
|
+
end
|
42
49
|
end
|
43
50
|
|
44
51
|
def check_config!
|
45
52
|
return if config.crystal_src_dir
|
46
53
|
|
47
|
-
raise "Missing config option `crystal_src_dir`. \nProvide this inside crystalruby.yaml "\
|
54
|
+
raise "Missing config option `crystal_src_dir`. \nProvide this inside crystalruby.yaml " \
|
48
55
|
"(run `bundle exec crystalruby init` to generate this file with detaults)"
|
49
56
|
end
|
50
57
|
|
51
58
|
%w[debug info warn error].each do |level|
|
52
|
-
define_method("log_#{level}") do |*msg|
|
59
|
+
define_method(:"log_#{level}") do |*msg|
|
53
60
|
prefix = config.colorize_log_output ? "\e[33mcrystalruby\e[0m\e[90m [#{Thread.current.object_id}]\e[0m" : "[crystalruby] #{Thread.current.object_id}"
|
54
61
|
|
55
62
|
config.logger.send(level, "#{prefix} #{msg.join(", ")}")
|