crystalruby 0.2.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/Dockerfile +23 -2
  4. data/README.md +395 -198
  5. data/Rakefile +4 -3
  6. data/crystalruby.gemspec +2 -2
  7. data/examples/adder/adder.rb +1 -1
  8. data/exe/crystalruby +1 -0
  9. data/lib/crystalruby/adapter.rb +143 -73
  10. data/lib/crystalruby/arc_mutex.rb +47 -0
  11. data/lib/crystalruby/compilation.rb +32 -3
  12. data/lib/crystalruby/config.rb +41 -37
  13. data/lib/crystalruby/function.rb +216 -73
  14. data/lib/crystalruby/library.rb +157 -51
  15. data/lib/crystalruby/reactor.rb +63 -44
  16. data/lib/crystalruby/source_reader.rb +92 -0
  17. data/lib/crystalruby/template.rb +16 -5
  18. data/lib/crystalruby/templates/function.cr +11 -10
  19. data/lib/crystalruby/templates/index.cr +53 -66
  20. data/lib/crystalruby/templates/inline_chunk.cr +1 -1
  21. data/lib/crystalruby/templates/ruby_interface.cr +34 -0
  22. data/lib/crystalruby/templates/top_level_function.cr +62 -0
  23. data/lib/crystalruby/templates/top_level_ruby_interface.cr +33 -0
  24. data/lib/crystalruby/typebuilder.rb +11 -55
  25. data/lib/crystalruby/typemaps.rb +92 -67
  26. data/lib/crystalruby/types/concerns/allocator.rb +80 -0
  27. data/lib/crystalruby/types/fixed_width/named_tuple.cr +80 -0
  28. data/lib/crystalruby/types/fixed_width/named_tuple.rb +86 -0
  29. data/lib/crystalruby/types/fixed_width/proc.cr +45 -0
  30. data/lib/crystalruby/types/fixed_width/proc.rb +79 -0
  31. data/lib/crystalruby/types/fixed_width/tagged_union.cr +53 -0
  32. data/lib/crystalruby/types/fixed_width/tagged_union.rb +113 -0
  33. data/lib/crystalruby/types/fixed_width/tuple.cr +82 -0
  34. data/lib/crystalruby/types/fixed_width/tuple.rb +92 -0
  35. data/lib/crystalruby/types/fixed_width.cr +138 -0
  36. data/lib/crystalruby/types/fixed_width.rb +205 -0
  37. data/lib/crystalruby/types/primitive.cr +21 -0
  38. data/lib/crystalruby/types/primitive.rb +117 -0
  39. data/lib/crystalruby/types/primitive_types/bool.cr +34 -0
  40. data/lib/crystalruby/types/primitive_types/bool.rb +11 -0
  41. data/lib/crystalruby/types/primitive_types/nil.cr +35 -0
  42. data/lib/crystalruby/types/primitive_types/nil.rb +16 -0
  43. data/lib/crystalruby/types/primitive_types/numbers.cr +37 -0
  44. data/lib/crystalruby/types/primitive_types/numbers.rb +28 -0
  45. data/lib/crystalruby/types/primitive_types/symbol.cr +55 -0
  46. data/lib/crystalruby/types/primitive_types/symbol.rb +35 -0
  47. data/lib/crystalruby/types/primitive_types/time.cr +35 -0
  48. data/lib/crystalruby/types/primitive_types/time.rb +25 -0
  49. data/lib/crystalruby/types/type.cr +64 -0
  50. data/lib/crystalruby/types/type.rb +249 -30
  51. data/lib/crystalruby/types/variable_width/array.cr +74 -0
  52. data/lib/crystalruby/types/variable_width/array.rb +88 -0
  53. data/lib/crystalruby/types/variable_width/hash.cr +146 -0
  54. data/lib/crystalruby/types/variable_width/hash.rb +117 -0
  55. data/lib/crystalruby/types/variable_width/string.cr +36 -0
  56. data/lib/crystalruby/types/variable_width/string.rb +18 -0
  57. data/lib/crystalruby/types/variable_width.cr +23 -0
  58. data/lib/crystalruby/types/variable_width.rb +46 -0
  59. data/lib/crystalruby/types.rb +32 -13
  60. data/lib/crystalruby/version.rb +2 -2
  61. data/lib/crystalruby.rb +13 -6
  62. metadata +42 -22
  63. data/lib/crystalruby/types/array.rb +0 -15
  64. data/lib/crystalruby/types/bool.rb +0 -3
  65. data/lib/crystalruby/types/hash.rb +0 -17
  66. data/lib/crystalruby/types/named_tuple.rb +0 -28
  67. data/lib/crystalruby/types/nil.rb +0 -3
  68. data/lib/crystalruby/types/numbers.rb +0 -5
  69. data/lib/crystalruby/types/string.rb +0 -3
  70. data/lib/crystalruby/types/symbol.rb +0 -3
  71. data/lib/crystalruby/types/time.rb +0 -8
  72. data/lib/crystalruby/types/tuple.rb +0 -17
  73. data/lib/crystalruby/types/type_serializer/json.rb +0 -41
  74. data/lib/crystalruby/types/type_serializer.rb +0 -37
  75. data/lib/crystalruby/types/typedef.rb +0 -57
  76. data/lib/crystalruby/types/union_type.rb +0 -43
  77. data/lib/module.rb +0 -3
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CrystalRuby::Types
4
+ Tuple = FixedWidth.build(
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
+ FixedWidth.build(:Tuple, inner_types: types, convert_if: [Root::Array], superclass: Tuple) do
11
+ @data_offset = 4
12
+
13
+ # We only accept List-like values, which have all of the required keys
14
+ # and values of the correct type
15
+ # can successfully be cast to our inner types
16
+ def self.cast!(value)
17
+ unless (value.is_a?(Array) || value.is_a?(Tuple) || value.is_a?(Root::Array)) && value.zip(inner_types).each do |v, t|
18
+ t && t.valid_cast?(v)
19
+ end && value.length == inner_types.length
20
+ raise CrystalRuby::InvalidCastError, "Cannot cast #{value} to #{inspect}"
21
+ end
22
+
23
+ value
24
+ end
25
+
26
+ def self.copy_to!(values, memory:)
27
+ data_pointer = malloc(memsize)
28
+
29
+ memory[data_offset].write_pointer(data_pointer)
30
+
31
+ inner_types.each.reduce(0) do |offset, type|
32
+ type.write_single(data_pointer[offset], values.shift)
33
+ offset + type.refsize
34
+ end
35
+ end
36
+
37
+ def self.each_child_address(pointer)
38
+ data_pointer = pointer[data_offset].read_pointer
39
+ inner_types.each do |type|
40
+ yield type, data_pointer
41
+ data_pointer += type.refsize
42
+ end
43
+ end
44
+
45
+ def self.memsize
46
+ inner_types.map(&:refsize).sum
47
+ end
48
+
49
+ def size
50
+ inner_types.size
51
+ end
52
+
53
+ def checked_offset!(index, size)
54
+ raise "Index out of bounds: #{index} >= #{size}" if index >= size
55
+
56
+ if index < 0
57
+ raise "Index out of bounds: #{index} < -#{size}" if index < -size
58
+
59
+ index += size
60
+ end
61
+ self.class.offset_for(index)
62
+ end
63
+
64
+ def self.offset_for(index)
65
+ inner_types[0...index].map(&:refsize).sum
66
+ end
67
+
68
+ # Return the element at the given index.
69
+ # This will automatically increment
70
+ # the reference count if not a primitive type.
71
+ def [](index)
72
+ inner_types[index].fetch_single(data_pointer[checked_offset!(index, size)])
73
+ end
74
+
75
+ # Overwrite the element at the given index
76
+ # The replaced element will have
77
+ # its reference count decremented.
78
+ def []=(index, value)
79
+ inner_types[index].write_single(data_pointer[checked_offset!(index, size)], value)
80
+ end
81
+
82
+ def value(native: false)
83
+ ptr = data_pointer
84
+ inner_types.map do |type|
85
+ result = type.fetch_single(ptr, native: native)
86
+ ptr += type.refsize
87
+ result
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,138 @@
1
+ module CrystalRuby
2
+ module Types
3
+ # For a fixed width type, we allocate a single block block of memory of the form
4
+ # [ref_count (uint32), data(uint8*)]
5
+ class FixedWidth < Type
6
+
7
+ # We can instantiate it with a Value (for a new object)
8
+ # or a Pointer (for a copy of an existing object)
9
+ macro inherited
10
+ def initialize(@memory : Pointer(::UInt8))
11
+ increment_ref_count!
12
+ end
13
+ end
14
+
15
+ def finalize
16
+ self.class.decrement_ref_count!(@memory)
17
+ end
18
+
19
+ def increment_ref_count!
20
+ self.class.increment_ref_count!(@memory)
21
+ end
22
+
23
+ def self.increment_ref_count!(memory, by=1)
24
+ as_int32_ptr = memory.as(Pointer(::UInt32))
25
+ synchronize{ as_int32_ptr[0] += by }
26
+ end
27
+
28
+ def self.decrement_ref_count!(memory, by=1)
29
+ as_int32_ptr = memory.as(Pointer(::UInt32))
30
+ synchronize{ as_int32_ptr[0] -= by }
31
+ free!(memory) if as_int32_ptr[0] == 0
32
+ end
33
+
34
+ def self.refsize
35
+ 8
36
+ end
37
+
38
+
39
+ def self.free!(memory)
40
+ # Decrease ref counts for any data we are pointing to
41
+ # Also responsible for freeing internal memory if ref count reaches zero
42
+ decr_inner_ref_counts!(memory)
43
+ # # Free slot memory
44
+ free(memory)
45
+ end
46
+
47
+ def self.decr_inner_ref_counts!(pointer)
48
+ self.each_child_address(pointer) do |child_type, child_address|
49
+ child_type.decrement_ref_count!(child_address.read_pointer)
50
+ end
51
+ # Free data block, if we're a variable with type.
52
+ as_pointer_ref = (pointer+data_offset).as(Pointer(Pointer(::UInt8)))
53
+ free(as_pointer_ref[0]) if variable_width?
54
+ end
55
+
56
+ def self.variable_width?
57
+ false
58
+ end
59
+
60
+ # Ref count is always the first UInt32 in the memory block
61
+ def ref_count
62
+ memory.as(Pointer(::UInt32))[0]
63
+ end
64
+
65
+ def ref_count=(val)
66
+ memory.as(Pointer(::UInt32))[0] = value
67
+ end
68
+
69
+ # Data pointer follows the ref count (and size for variable width types)
70
+ # In the case of variable width types the data pointer points to the start of a separate data block
71
+ # So this method is overridden inside variable_width.rb to resolve this pointer.
72
+ def data_pointer : Pointer(UInt8)
73
+ (memory + data_offset)
74
+ end
75
+
76
+ # Create a brand new copy of this object
77
+ def deep_dup
78
+ self.class.new(value)
79
+ end
80
+
81
+ # Create a new reference to this object.
82
+ def dup
83
+ self.class.new(@memory)
84
+ end
85
+
86
+ def address
87
+ memory.address
88
+ end
89
+
90
+ def data_offset
91
+ self.class.data_offset
92
+ end
93
+
94
+ def memsize
95
+ self.class.memsize
96
+ end
97
+
98
+ def size_offset
99
+ self.class.size_offset
100
+ end
101
+
102
+ def self.size_offset
103
+ 4
104
+ end
105
+
106
+ def self.data_offset
107
+ 4
108
+ end
109
+
110
+ # Read a value of this type from the
111
+ # contained pointer at a given index
112
+ def self.fetch_single(pointer : Pointer(::UInt8))
113
+ value_pointer = pointer.as(Pointer(Pointer(::UInt8)))
114
+ new(value_pointer.value)
115
+ end
116
+
117
+ # Write a data type into a pointer at a given index
118
+ # (Type can be a byte-array, pointer or numeric type
119
+ #
120
+ # )
121
+ def self.write_single(pointer, value)
122
+ value_pointer = pointer.as(Pointer(Pointer(::UInt8)))
123
+ if !value_pointer[0].null?
124
+ decrement_ref_count!(value_pointer[0])
125
+ end
126
+ memory = malloc(self.data_offset + self.memsize)
127
+
128
+ self.copy_to!(value, memory)
129
+ value_pointer.value = memory
130
+ increment_ref_count!(memory)
131
+ end
132
+
133
+ # Fetch an array of a given data type from a list pointer
134
+ # (Type can be a byte-array, pointer or numeric type)
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,205 @@
1
+ module CrystalRuby
2
+ module Types
3
+ # For a fixed width type, we allocate a single block block of memory of the form
4
+ # [ref_count (uint32), data(uint8*)]
5
+ class FixedWidth < Type
6
+ # We can instantiate it with a Value (for a new object)
7
+ # or a Pointer (for a copy of an existing object)
8
+ def initialize(rbval)
9
+ super
10
+ case rbval
11
+ when FFI::Pointer then allocate_new_from_reference!(rbval)
12
+ else allocate_new_from_value!(rbval)
13
+ end
14
+ self.class.increment_ref_count!(memory)
15
+ ObjectSpace.define_finalizer(self, self.class.finalize(memory))
16
+ end
17
+
18
+ def self.finalize(memory)
19
+ lambda { |_|
20
+ decrement_ref_count!(memory)
21
+ }
22
+ end
23
+
24
+ def allocate_new_from_value!(rbval)
25
+ # New block of memory, to hold our object.
26
+ # For variable with, this is 2x UInt32 for ref count and size, plus a data pointer (8 bytes)
27
+ # Layout:
28
+ # - ref_count (4 bytes)
29
+ # - size (4 bytes)
30
+ # - data (8 bytes)
31
+ #
32
+ # For fixed the data is inline
33
+ # Layout:
34
+ # - ref_count (4 bytes)
35
+ # - size (0 bytes) (No size for fixed width types)
36
+ # - data (memsize bytes)
37
+ self.memory = malloc(refsize + data_offset)
38
+ self.value = rbval
39
+ end
40
+
41
+ def allocate_new_from_reference!(memory)
42
+ # When we point to an existing block of memory, we don't need to allocate anything.
43
+ # This memory should be to a single, separately allocated block of the above size.
44
+ # When this type is contained within another type, it should be as a pointer to this block (not the contents of the block itself).
45
+ self.memory = memory
46
+ end
47
+
48
+ # Each type should be convertible to an FFI representation. (I.e. how is a value or reference to this value stored
49
+ # within e.g. an Array, Hash, Tuple or any other containing type).
50
+ # For both fixed and variable types these are simply stored within
51
+ # the containing type as a pointer to the memory block.
52
+ # We return the pointer to this memory here.
53
+ def self.to_ffi_repr(value)
54
+ to_store = new(value)
55
+ increment_ref_count!(to_store.memory)
56
+ to_store.memory
57
+ end
58
+
59
+ # Read a value of this type from the
60
+ # contained pointer at a given index
61
+ def self.fetch_single(pointer, native: false)
62
+ # Nothing to fetch for Nils
63
+ return if memsize.zero?
64
+
65
+ value_pointer = pointer.read_pointer
66
+ native ? new(value_pointer).native : new(value_pointer)
67
+ end
68
+
69
+ # Write a data type into a pointer at a given index
70
+ # (Type can be a byte-array, pointer or numeric type
71
+ #
72
+ # )
73
+ def self.write_single(pointer, value)
74
+ # Dont need to write nils
75
+ return if memsize.zero?
76
+
77
+ decrement_ref_count!(pointer.read_pointer) unless pointer.read_pointer.null?
78
+ memory = malloc(refsize + data_offset)
79
+ copy_to!(cast!(value), memory: memory)
80
+ increment_ref_count!(memory)
81
+ pointer.write_pointer(memory)
82
+ end
83
+
84
+ # Fetch an array of a given data type from a list pointer
85
+ # (Type can be a byte-array, pointer or numeric type)
86
+ def self.fetch_multi(pointer, size, native: false)
87
+ size.times.map { |i| fetch_single(pointer[i * refsize], native: native) }
88
+ end
89
+
90
+ def self.increment_ref_count!(memory, by = 1)
91
+ synchronize { memory.write_int32(memory.read_int32 + by) }
92
+ end
93
+
94
+ def self.decrement_ref_count!(memory, by = 1)
95
+ synchronize { memory.write_int32(memory.read_int32 - by) }
96
+ return unless memory.read_int32.zero?
97
+
98
+ free!(memory)
99
+ end
100
+
101
+ def self.free!(memory)
102
+ # Decrease ref counts for any data we are pointing to
103
+ # Also responsible for freeing internal memory if ref count reaches zero
104
+ decr_inner_ref_counts!(memory)
105
+
106
+ # # Free slot memory
107
+ free(memory)
108
+ end
109
+
110
+ def self.decr_inner_ref_counts!(pointer)
111
+ each_child_address(pointer) do |child_type, child_address|
112
+ child_type.decrement_ref_count!(child_address.read_pointer) if child_type.fixed_width?
113
+ end
114
+ # Free data block, if we're a variable width type.
115
+ return unless variable_width?
116
+
117
+ free(pointer[data_offset].read_pointer)
118
+ end
119
+
120
+ # Ref count is always the first Int32 in the memory block
121
+ def ref_count
122
+ memory.read_uint32
123
+ end
124
+
125
+ def ref_count=(val)
126
+ memory.write_int32(val)
127
+ end
128
+
129
+ # Data pointer follows the ref count (and size for variable width types)
130
+ # In the case of variable width types the data pointer points to the start of a separate data block
131
+ # So this method is overridden inside variable_width.rb to resolve this pointer.
132
+ def data_pointer
133
+ memory[data_offset].read_pointer
134
+ end
135
+
136
+ def size
137
+ memory[size_offset].read_int32
138
+ end
139
+
140
+ def address
141
+ @memory.address
142
+ end
143
+
144
+ def self.crystal_supertype
145
+ "CrystalRuby::Types::FixedWidth"
146
+ end
147
+
148
+ def self.crystal_type
149
+ "Pointer(::UInt8)"
150
+ end
151
+
152
+ # If we are fixed with,
153
+ # The memory we allocate a single block of memory, if not already given.
154
+ # Within this block of memory, we copy our contents directly.
155
+ #
156
+ # If we are variable width, we allocate a small block of memory for the pointer only
157
+ # and allocate a separate block of memory for the data.
158
+ # We store the pointer to the data in the memory block.
159
+
160
+ def value=(value)
161
+ # If we're already pointing at something
162
+ # Decrement the ref counts of anything we're pointing at
163
+ value = cast!(value)
164
+
165
+ self.class.decr_inner_ref_counts!(memory) if ref_count > 0
166
+ self.class.copy_to!(value, memory: memory)
167
+ end
168
+
169
+ # Build a new FixedWith subtype
170
+ # Layout varies according to the sizes of internal types
171
+ def self.build(
172
+ typename = nil,
173
+ error: nil,
174
+ inner_types: nil,
175
+ inner_keys: nil,
176
+ ffi_type: :pointer,
177
+ memsize: FFI.type_size(ffi_type),
178
+ refsize: 8,
179
+ convert_if: [],
180
+ superclass: FixedWidth,
181
+ size_offset: 4,
182
+ data_offset: 4,
183
+ &block
184
+ )
185
+ inner_types&.each(&Type.method(:validate!))
186
+
187
+ Class.new(superclass) do
188
+ bind_local_vars!(
189
+ %i[typename error inner_types inner_keys ffi_type memsize convert_if size_offset data_offset
190
+ refsize], binding
191
+ )
192
+ class_eval(&block) if block_given?
193
+
194
+ def self.fixed_width?
195
+ true
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ require_relative "fixed_width/proc"
203
+ require_relative "fixed_width/named_tuple"
204
+ require_relative "fixed_width/tuple"
205
+ require_relative "fixed_width/tagged_union"
@@ -0,0 +1,21 @@
1
+ module CrystalRuby
2
+ module Types
3
+ class Primitive < Type
4
+ def return_value
5
+ @value
6
+ end
7
+
8
+ def native
9
+ value
10
+ end
11
+
12
+ def self.fetch_single(pointer : Pointer(::UInt8))
13
+ new(pointer)
14
+ end
15
+
16
+ def self.refsize
17
+ self.memsize
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,117 @@
1
+ module CrystalRuby
2
+ module Types
3
+ class Primitive < Type
4
+ # Primitives just store the Ruby value directly
5
+ # (Or read it from memory if passed a pointer)
6
+ def initialize(rbval)
7
+ super(rbval)
8
+ self.value = rbval.is_a?(FFI::Pointer) ? rbval.send("read_#{ffi_type}") : rbval
9
+ end
10
+
11
+ # Read a value from a pointer at a given index
12
+ # (Type can be a byte-array, pointer or numeric type)
13
+ def self.fetch_single(pointer, native: false)
14
+ # Nothing to fetch for Nils
15
+ return if memsize.zero?
16
+
17
+ if numeric?
18
+ pointer.send("read_#{ffi_type}")
19
+ elsif primitive?
20
+ single = new(pointer.send("read_#{ffi_type}"))
21
+ if native
22
+ single.value
23
+ else
24
+ single
25
+ end
26
+ end
27
+ end
28
+
29
+ # Write a data type into a pointer at a given index
30
+ # (Type can be a byte-array, pointer or numeric type)
31
+ def self.write_single(pointer, value)
32
+ # Dont need to write nils
33
+ return if memsize.zero?
34
+
35
+ pointer.send("write_#{ffi_type}", to_ffi_repr(value))
36
+ end
37
+
38
+ # Fetch an array of a given data type from a list pointer
39
+ # (Type can be a byte-array, pointer or numeric type)
40
+ def self.fetch_multi(pointer, size, native: false)
41
+ if numeric?
42
+ pointer.send("get_array_of_#{ffi_type}", 0, size)
43
+ elsif primitive?
44
+ pointer.send("get_array_of_#{ffi_type}", 0, size).map(&method(:from_ffi_array_repr))
45
+ end
46
+ end
47
+
48
+ def self.decrement_ref_count!(pointer)
49
+ # Do nothing
50
+ end
51
+
52
+ # Define a new primitive type
53
+ # Primitive types are stored by value
54
+ # and efficiently copied using native FFI types
55
+ # They are written directly into the memory of a container type
56
+ # (No indirection)
57
+ def self.build(
58
+ typename = nil,
59
+ ffi_type: :uint8,
60
+ memsize: FFI.type_size(ffi_type),
61
+ convert_if: [],
62
+ error: nil,
63
+ superclass: Primitive,
64
+ &block
65
+ )
66
+ Class.new(superclass) do
67
+ %w[typename ffi_type memsize convert_if error].each do |name|
68
+ define_singleton_method(name) { binding.local_variable_get("#{name}") }
69
+ define_method(name) { binding.local_variable_get("#{name}") }
70
+ end
71
+
72
+ class_eval(&block) if block_given?
73
+
74
+ # Primitives are stored directly in memory as a raw numeric value
75
+ def self.to_ffi_repr(value)
76
+ new(value).inner_value
77
+ end
78
+
79
+ def self.refsize
80
+ memsize
81
+ end
82
+
83
+ # Primiives are anonymous (Shouldn't be subclassed)
84
+ def self.anonymous?
85
+ true
86
+ end
87
+
88
+ def self.copy_to!(rbval, memory:)
89
+ memory.send("write_#{self.ffi_type}", to_ffi_repr(rbval))
90
+ end
91
+
92
+ def self.primitive?
93
+ true
94
+ end
95
+
96
+ def self.inspect
97
+ inspect_name
98
+ end
99
+
100
+ def memory
101
+ @value
102
+ end
103
+
104
+ def self.crystal_supertype
105
+ "CrystalRuby::Types::Primitive"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ require_relative "primitive_types/time"
114
+ require_relative "primitive_types/symbol"
115
+ require_relative "primitive_types/numbers"
116
+ require_relative "primitive_types/nil"
117
+ require_relative "primitive_types/bool"
@@ -0,0 +1,34 @@
1
+ class <%= base_crystal_class_name %> < CrystalRuby::Types::Primitive
2
+
3
+ def initialize(value : ::Bool)
4
+ @value = value ? 1_u8 : 0_u8
5
+ end
6
+
7
+ def initialize(ptr : Pointer(::UInt8))
8
+ @value = ptr[0]
9
+ end
10
+
11
+ def initialize(value : UInt8)
12
+ @value = value
13
+ end
14
+
15
+ def value=(value : ::Bool)
16
+ @value = value ? 1_u8 : 0_u8
17
+ end
18
+
19
+ def value : <%= native_type_expr %>
20
+ @value == 1_u8
21
+ end
22
+
23
+ def ==(other : ::Bool)
24
+ value == other
25
+ end
26
+
27
+ def self.memsize
28
+ <%= memsize %>
29
+ end
30
+
31
+ def self.write_single(pointer : Pointer(::UInt8), value)
32
+ pointer.as(Pointer(::UInt8)).value = value ? 1_u8 : 0_u8
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module CrystalRuby::Types
2
+ Bool = Primitive.build(:Bool, convert_if: [::TrueClass, ::FalseClass], ffi_type: :uint8, memsize: 1) do
3
+ def value(native: false)
4
+ super == 1
5
+ end
6
+
7
+ def value=(val)
8
+ !!val && val != 0 ? super(1) : super(0)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ class <%= base_crystal_class_name %> < CrystalRuby::Types::Primitive
2
+
3
+ property value : ::Nil = nil
4
+
5
+ def initialize(nilval : ::Nil)
6
+ end
7
+
8
+ def initialize(ptr : Pointer(::UInt8))
9
+ end
10
+
11
+ def initialize(raw : UInt8)
12
+ end
13
+
14
+ def value : ::Nil
15
+ nil
16
+ end
17
+
18
+ def ==(other : ::Nil)
19
+ value.nil?
20
+ end
21
+
22
+ def value=(val : ::Nil)
23
+ end
24
+
25
+ def self.memsize
26
+ 0
27
+ end
28
+
29
+ def return_value
30
+ 0_u8
31
+ end
32
+
33
+ def self.write_single(pointer : Pointer(::UInt8), value)
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module CrystalRuby::Types
2
+ Nil = Primitive.build(:Nil, convert_if: [::NilClass], memsize: 0) do
3
+ def initialize(val = nil)
4
+ super
5
+ @value = 0
6
+ end
7
+
8
+ def nil?
9
+ true
10
+ end
11
+
12
+ def value(native: false)
13
+ nil
14
+ end
15
+ end
16
+ end