crystalruby 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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"