crystalruby 0.2.3 → 0.3.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/README.md +389 -193
  4. data/Rakefile +4 -3
  5. data/crystalruby.gemspec +2 -2
  6. data/exe/crystalruby +1 -0
  7. data/lib/crystalruby/adapter.rb +131 -65
  8. data/lib/crystalruby/arc_mutex.rb +47 -0
  9. data/lib/crystalruby/compilation.rb +32 -3
  10. data/lib/crystalruby/config.rb +41 -37
  11. data/lib/crystalruby/function.rb +211 -68
  12. data/lib/crystalruby/library.rb +153 -48
  13. data/lib/crystalruby/reactor.rb +40 -23
  14. data/lib/crystalruby/source_reader.rb +86 -0
  15. data/lib/crystalruby/template.rb +16 -5
  16. data/lib/crystalruby/templates/function.cr +11 -10
  17. data/lib/crystalruby/templates/index.cr +53 -66
  18. data/lib/crystalruby/templates/inline_chunk.cr +1 -1
  19. data/lib/crystalruby/templates/ruby_interface.cr +34 -0
  20. data/lib/crystalruby/templates/top_level_function.cr +62 -0
  21. data/lib/crystalruby/templates/top_level_ruby_interface.cr +33 -0
  22. data/lib/crystalruby/typebuilder.rb +11 -55
  23. data/lib/crystalruby/typemaps.rb +92 -67
  24. data/lib/crystalruby/types/concerns/allocator.rb +80 -0
  25. data/lib/crystalruby/types/fixed_width/named_tuple.cr +80 -0
  26. data/lib/crystalruby/types/fixed_width/named_tuple.rb +86 -0
  27. data/lib/crystalruby/types/fixed_width/proc.cr +45 -0
  28. data/lib/crystalruby/types/fixed_width/proc.rb +79 -0
  29. data/lib/crystalruby/types/fixed_width/tagged_union.cr +53 -0
  30. data/lib/crystalruby/types/fixed_width/tagged_union.rb +109 -0
  31. data/lib/crystalruby/types/fixed_width/tuple.cr +82 -0
  32. data/lib/crystalruby/types/fixed_width/tuple.rb +92 -0
  33. data/lib/crystalruby/types/fixed_width.cr +138 -0
  34. data/lib/crystalruby/types/fixed_width.rb +205 -0
  35. data/lib/crystalruby/types/primitive.cr +21 -0
  36. data/lib/crystalruby/types/primitive.rb +117 -0
  37. data/lib/crystalruby/types/primitive_types/bool.cr +34 -0
  38. data/lib/crystalruby/types/primitive_types/bool.rb +11 -0
  39. data/lib/crystalruby/types/primitive_types/nil.cr +35 -0
  40. data/lib/crystalruby/types/primitive_types/nil.rb +16 -0
  41. data/lib/crystalruby/types/primitive_types/numbers.cr +37 -0
  42. data/lib/crystalruby/types/primitive_types/numbers.rb +28 -0
  43. data/lib/crystalruby/types/primitive_types/symbol.cr +55 -0
  44. data/lib/crystalruby/types/primitive_types/symbol.rb +35 -0
  45. data/lib/crystalruby/types/primitive_types/time.cr +35 -0
  46. data/lib/crystalruby/types/primitive_types/time.rb +25 -0
  47. data/lib/crystalruby/types/type.cr +64 -0
  48. data/lib/crystalruby/types/type.rb +239 -30
  49. data/lib/crystalruby/types/variable_width/array.cr +74 -0
  50. data/lib/crystalruby/types/variable_width/array.rb +88 -0
  51. data/lib/crystalruby/types/variable_width/hash.cr +146 -0
  52. data/lib/crystalruby/types/variable_width/hash.rb +117 -0
  53. data/lib/crystalruby/types/variable_width/string.cr +36 -0
  54. data/lib/crystalruby/types/variable_width/string.rb +18 -0
  55. data/lib/crystalruby/types/variable_width.cr +23 -0
  56. data/lib/crystalruby/types/variable_width.rb +46 -0
  57. data/lib/crystalruby/types.rb +32 -13
  58. data/lib/crystalruby/version.rb +2 -2
  59. data/lib/crystalruby.rb +13 -6
  60. metadata +41 -19
  61. data/lib/crystalruby/types/array.rb +0 -15
  62. data/lib/crystalruby/types/bool.rb +0 -3
  63. data/lib/crystalruby/types/hash.rb +0 -17
  64. data/lib/crystalruby/types/named_tuple.rb +0 -28
  65. data/lib/crystalruby/types/nil.rb +0 -3
  66. data/lib/crystalruby/types/numbers.rb +0 -5
  67. data/lib/crystalruby/types/string.rb +0 -3
  68. data/lib/crystalruby/types/symbol.rb +0 -3
  69. data/lib/crystalruby/types/time.rb +0 -8
  70. data/lib/crystalruby/types/tuple.rb +0 -17
  71. data/lib/crystalruby/types/type_serializer/json.rb +0 -41
  72. data/lib/crystalruby/types/type_serializer.rb +0 -37
  73. data/lib/crystalruby/types/typedef.rb +0 -57
  74. data/lib/crystalruby/types/union_type.rb +0 -43
  75. data/lib/module.rb +0 -3
@@ -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"
@@ -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"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Crystalruby
4
- VERSION = "0.2.3"
3
+ module CrystalRuby
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/crystalruby.rb CHANGED
@@ -3,11 +3,12 @@
3
3
  require "ffi"
4
4
  require "digest"
5
5
  require "fileutils"
6
- require "method_source"
6
+ require "syntax_tree"
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 "module"
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
- raise "Crystal executable not found. Please ensure Crystal is installed and in your PATH." \
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(", ")}")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crystalruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-09 00:00:00.000000000 Z
11
+ date: 2024-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digest
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: method_source
56
+ name: syntax_tree
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -87,35 +87,57 @@ files:
87
87
  - exe/crystalruby
88
88
  - lib/crystalruby.rb
89
89
  - lib/crystalruby/adapter.rb
90
+ - lib/crystalruby/arc_mutex.rb
90
91
  - lib/crystalruby/compilation.rb
91
92
  - lib/crystalruby/config.rb
92
93
  - lib/crystalruby/function.rb
93
94
  - lib/crystalruby/library.rb
94
95
  - lib/crystalruby/reactor.rb
96
+ - lib/crystalruby/source_reader.rb
95
97
  - lib/crystalruby/template.rb
96
98
  - lib/crystalruby/templates/function.cr
97
99
  - lib/crystalruby/templates/index.cr
98
100
  - lib/crystalruby/templates/inline_chunk.cr
101
+ - lib/crystalruby/templates/ruby_interface.cr
102
+ - lib/crystalruby/templates/top_level_function.cr
103
+ - lib/crystalruby/templates/top_level_ruby_interface.cr
99
104
  - lib/crystalruby/typebuilder.rb
100
105
  - lib/crystalruby/typemaps.rb
101
106
  - lib/crystalruby/types.rb
102
- - lib/crystalruby/types/array.rb
103
- - lib/crystalruby/types/bool.rb
104
- - lib/crystalruby/types/hash.rb
105
- - lib/crystalruby/types/named_tuple.rb
106
- - lib/crystalruby/types/nil.rb
107
- - lib/crystalruby/types/numbers.rb
108
- - lib/crystalruby/types/string.rb
109
- - lib/crystalruby/types/symbol.rb
110
- - lib/crystalruby/types/time.rb
111
- - lib/crystalruby/types/tuple.rb
107
+ - lib/crystalruby/types/concerns/allocator.rb
108
+ - lib/crystalruby/types/fixed_width.cr
109
+ - lib/crystalruby/types/fixed_width.rb
110
+ - lib/crystalruby/types/fixed_width/named_tuple.cr
111
+ - lib/crystalruby/types/fixed_width/named_tuple.rb
112
+ - lib/crystalruby/types/fixed_width/proc.cr
113
+ - lib/crystalruby/types/fixed_width/proc.rb
114
+ - lib/crystalruby/types/fixed_width/tagged_union.cr
115
+ - lib/crystalruby/types/fixed_width/tagged_union.rb
116
+ - lib/crystalruby/types/fixed_width/tuple.cr
117
+ - lib/crystalruby/types/fixed_width/tuple.rb
118
+ - lib/crystalruby/types/primitive.cr
119
+ - lib/crystalruby/types/primitive.rb
120
+ - lib/crystalruby/types/primitive_types/bool.cr
121
+ - lib/crystalruby/types/primitive_types/bool.rb
122
+ - lib/crystalruby/types/primitive_types/nil.cr
123
+ - lib/crystalruby/types/primitive_types/nil.rb
124
+ - lib/crystalruby/types/primitive_types/numbers.cr
125
+ - lib/crystalruby/types/primitive_types/numbers.rb
126
+ - lib/crystalruby/types/primitive_types/symbol.cr
127
+ - lib/crystalruby/types/primitive_types/symbol.rb
128
+ - lib/crystalruby/types/primitive_types/time.cr
129
+ - lib/crystalruby/types/primitive_types/time.rb
130
+ - lib/crystalruby/types/type.cr
112
131
  - lib/crystalruby/types/type.rb
113
- - lib/crystalruby/types/type_serializer.rb
114
- - lib/crystalruby/types/type_serializer/json.rb
115
- - lib/crystalruby/types/typedef.rb
116
- - lib/crystalruby/types/union_type.rb
132
+ - lib/crystalruby/types/variable_width.cr
133
+ - lib/crystalruby/types/variable_width.rb
134
+ - lib/crystalruby/types/variable_width/array.cr
135
+ - lib/crystalruby/types/variable_width/array.rb
136
+ - lib/crystalruby/types/variable_width/hash.cr
137
+ - lib/crystalruby/types/variable_width/hash.rb
138
+ - lib/crystalruby/types/variable_width/string.cr
139
+ - lib/crystalruby/types/variable_width/string.rb
117
140
  - lib/crystalruby/version.rb
118
- - lib/module.rb
119
141
  - logo.png
120
142
  - sig/crystalruby.rbs
121
143
  homepage: https://github.com/wouterken/crystalruby
@@ -140,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
162
  - !ruby/object:Gem::Version
141
163
  version: '0'
142
164
  requirements: []
143
- rubygems_version: 3.4.19
165
+ rubygems_version: 3.5.3
144
166
  signing_key:
145
167
  specification_version: 4
146
168
  summary: Embed Crystal code directly in Ruby.
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CrystalRuby::Types
4
- Array = Type.new(
5
- :Array,
6
- error: "Array type must have a type parameter. E.g. Array(Float64)"
7
- )
8
-
9
- def self.Array(type)
10
- Type.validate!(type)
11
- Type.new("Array", inner_types: [type], accept_if: [::Array]) do |a|
12
- a.map! { |v| type.interpret!(v) }
13
- end
14
- end
15
- end
@@ -1,3 +0,0 @@
1
- module CrystalRuby::Types
2
- Bool = Type.new(:Bool, accept_if: [::TrueClass, ::FalseClass])
3
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CrystalRuby::Types
4
- Hash = Type.new(
5
- :Hash,
6
- error: "Hash type must have 2 type parameters. E.g. Hash(Float64, String)"
7
- )
8
-
9
- def self.Hash(key_type, value_type)
10
- Type.validate!(key_type)
11
- Type.validate!(value_type)
12
- Type.new("Hash", inner_types: [key_type, value_type], accept_if: [::Hash]) do |h|
13
- h.transform_keys! { |k| key_type.interpret!(k) }
14
- h.transform_values! { |v| value_type.interpret!(v) }
15
- end
16
- end
17
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CrystalRuby::Types
4
- NamedTuple = Type.new(
5
- :NamedTuple,
6
- error: "NamedTuple type must contain one or more symbol -> type pairs. E.g. NamedTuple(hello: Int32, world: String)"
7
- )
8
-
9
- def self.NamedTuple(types_hash)
10
- types_hash.keys.each do |key|
11
- raise "NamedTuple keys must be symbols" unless key.is_a?(::Symbol) || key.respond_to?(:to_sym)
12
- end
13
- types_hash.values.each do |value_type|
14
- Type.validate!(value_type)
15
- end
16
- keys = types_hash.keys.map(&:to_sym)
17
- values = types_hash.values
18
- Type.new("NamedTuple", inner_types: values, inner_keys: keys, accept_if: [::Hash]) do |h|
19
- h.transform_keys! { |k| k.to_sym }
20
- raise "Invalid keys for named tuple" unless h.keys.length == keys.length
21
- raise "Invalid keys for named tuple" unless h.keys.all? { |k| keys.include?(k) }
22
-
23
- h.each do |key, value|
24
- h[key] = values[keys.index(key)].interpret!(value)
25
- end
26
- end
27
- end
28
- end
@@ -1,3 +0,0 @@
1
- module CrystalRuby::Types
2
- Nil = Type.new(:Nil, accept_if: [::NilClass])
3
- end
@@ -1,5 +0,0 @@
1
- module CrystalRuby::Types
2
- %i[Uint8 Uint16 Uint32 Uint64 Int8 Int16 Int32 Int64 Float32 Float64].each do |type_name|
3
- const_set type_name, Type.new(type_name, accept_if: [::Numeric])
4
- end
5
- end
@@ -1,3 +0,0 @@
1
- module CrystalRuby::Types
2
- String = Type.new(:String, accept_if: [::String])
3
- end
@@ -1,3 +0,0 @@
1
- module CrystalRuby::Types
2
- Symbol = Type.new(:Symbol, accept_if: [::String, ::Symbol])
3
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CrystalRuby::Types
4
- require "date"
5
- Time = Type.new(:Time, accept_if: [::Time, ::String]) do |v|
6
- DateTime.parse(v)
7
- end
8
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CrystalRuby::Types
4
- Tuple = Type.new(
5
- :Tuple,
6
- error: "Tuple type must contain one or more types E.g. Tuple(Int32, String)"
7
- )
8
-
9
- def self.Tuple(*types)
10
- types.each do |value_type|
11
- Type.validate!(value_type)
12
- end
13
- Type.new("Tuple", inner_types: types, accept_if: [::Array]) do |a|
14
- a.map!.with_index { |v, i| inner_types[i].interpret!(v) }
15
- end
16
- end
17
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- module CrystalRuby::Types
6
- class TypeSerializer
7
- class JSON < TypeSerializer
8
- def lib_type
9
- "UInt8*"
10
- end
11
-
12
- def crystal_type
13
- type_expr
14
- end
15
-
16
- def error_value
17
- '"{}".to_unsafe'
18
- end
19
-
20
- def ffi_type
21
- :string
22
- end
23
-
24
- def prepare_argument(arg)
25
- arg.to_json
26
- end
27
-
28
- def prepare_retval(retval)
29
- @typedef.interpret!(::JSON.parse(retval))
30
- end
31
-
32
- def lib_to_crystal_type_expr(expr)
33
- "(#{type_expr}).from_json(String.new(%s))" % expr
34
- end
35
-
36
- def crystal_to_lib_type_expr(expr)
37
- "%s.to_json.to_unsafe" % expr
38
- end
39
- end
40
- end
41
- end
@@ -1,37 +0,0 @@
1
- module CrystalRuby::Types
2
- class TypeSerializer
3
- include FFI::DataConverter
4
- def self.for(format)
5
- case format
6
- when :json then JSON
7
- else raise "Unknown type format: #{format}"
8
- end
9
- end
10
-
11
- def error_value
12
- 0
13
- end
14
-
15
- def initialize(typedef)
16
- @typedef = typedef
17
- end
18
-
19
- def type_expr
20
- @typedef.type_expr
21
- end
22
-
23
- def type_defn
24
- @typedef.type_defn
25
- end
26
-
27
- def anonymous?
28
- @typedef.anonymous?
29
- end
30
-
31
- def name
32
- @typedef.name
33
- end
34
- end
35
- end
36
-
37
- require_relative "type_serializer/json"