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.
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