Class: CrystalRuby::Types::Type

Inherits:
Object
  • Object
show all
Extended by:
CrystalRuby::Typemaps
Includes:
Allocator
Defined in:
lib/crystalruby/types/type.rb

Direct Known Subclasses

FixedWidth, Primitive

Constant Summary collapse

ARC_MUTEX =

TODO: Replace with pthread primitives and share with Crystal

CrystalRuby::ArcMutex.new

Constants included from CrystalRuby::Typemaps

CrystalRuby::Typemaps::CRYSTAL_TYPE_MAP, CrystalRuby::Typemaps::C_TYPE_CONVERSIONS, CrystalRuby::Typemaps::C_TYPE_MAP, CrystalRuby::Typemaps::ERROR_VALUE, CrystalRuby::Typemaps::FFI_TYPE_MAP

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CrystalRuby::Typemaps

build_type_map, convert_crystal_to_lib_type, convert_lib_to_crystal_type, crystal_type, error_value, ffi_type, lib_type

Methods included from Allocator

gc_bytes_seen, gc_hint!, gc_hint_reset!, included

Constructor Details

#initialize(_rbval) ⇒ Type

Returns a new instance of Type.



52
53
54
55
# File 'lib/crystalruby/types/type.rb', line 52

def initialize(_rbval)
  @class = self.class
  raise error if error
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/crystalruby/types/type.rb', line 209

def method_missing(method, *args, &block)
  v = begin
    native
  rescue StandardError
    super
  end
  if v.respond_to?(method)
    hash_before = v.hash
    result = v.send(method, *args, &block)
    if v.hash != hash_before
      self.value = v
      v.equal?(result) ? self : result
    else
      result
    end
  else
    super
  end
end

Class Attribute Details

.convert_ifObject

Returns the value of attribute convert_if.



42
43
44
# File 'lib/crystalruby/types/type.rb', line 42

def convert_if
  @convert_if
end

.ffi_typeObject

Returns the value of attribute ffi_type.



42
43
44
# File 'lib/crystalruby/types/type.rb', line 42

def ffi_type
  @ffi_type
end

.inner_typesObject

Returns the value of attribute inner_types.



42
43
44
# File 'lib/crystalruby/types/type.rb', line 42

def inner_types
  @inner_types
end

.memsizeObject

Returns the value of attribute memsize.



42
43
44
# File 'lib/crystalruby/types/type.rb', line 42

def memsize
  @memsize
end

.typenameObject

Returns the value of attribute typename.



42
43
44
# File 'lib/crystalruby/types/type.rb', line 42

def typename
  @typename
end

Instance Attribute Details

#ffi_primitiveObject

Returns the value of attribute ffi_primitive.



50
51
52
# File 'lib/crystalruby/types/type.rb', line 50

def ffi_primitive
  @ffi_primitive
end

#memoryObject

Returns the value of attribute memory.



50
51
52
# File 'lib/crystalruby/types/type.rb', line 50

def memory
  @memory
end

#value(native: false) ⇒ Object

Returns the value of attribute value.



50
51
52
# File 'lib/crystalruby/types/type.rb', line 50

def value
  @value
end

Class Method Details

.[](*value) ⇒ Object



97
98
99
100
# File 'lib/crystalruby/types/type.rb', line 97

def self.[](*value)
  is_list_type = ancestors.any? { |a| a < CrystalRuby::Types::Array || a < CrystalRuby::Types::Tuple }
  new(is_list_type ? value : value.first)
end

.anonymous?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/crystalruby/types/type.rb', line 102

def self.anonymous?
  name.nil? || name.start_with?("CrystalRuby::Types::")
end

.base_crystal_class_nameObject



115
116
117
# File 'lib/crystalruby/types/type.rb', line 115

def self.base_crystal_class_name
  crystal_class_name.split("::").last
end

.bind_local_vars!(variable_names, binding) ⇒ Object



229
230
231
232
233
234
235
236
237
238
# File 'lib/crystalruby/types/type.rb', line 229

def self.bind_local_vars!(variable_names, binding)
  variable_names.each do |name|
    define_singleton_method(name) do
      binding.local_variable_get("#{name}")
    end
    define_method(name) do
      binding.local_variable_get("#{name}")
    end
  end
end

.cast!(value) ⇒ Object



171
172
173
# File 'lib/crystalruby/types/type.rb', line 171

def self.cast!(value)
  value.is_a?(Type) ? value.value : value
end

.crystal_class_nameObject



106
107
108
109
110
111
112
113
# File 'lib/crystalruby/types/type.rb', line 106

def self.crystal_class_name
  name || named_type_expr.split(",").join("_and_")
                         .split("|").join("_or_")
                         .split("(").join("_of_")
                         .gsub(/[^a-zA-Z0-9_]/, "")
                         .split("_")
                         .map(&:capitalize).join << "_#{type_digest[0..6]}"
end

.crystal_typeObject



257
258
259
# File 'lib/crystalruby/types/type.rb', line 257

def self.crystal_type
  lib_type(ffi_type)
end

.crystal_type_to_pointer_type_conversion(expr) ⇒ Object



139
140
141
# File 'lib/crystalruby/types/type.rb', line 139

def self.crystal_type_to_pointer_type_conversion(expr)
  anonymous? ? "#{crystal_class_name}.new(#{expr}).return_value" : "#{expr}.return_value"
end

.each_child_address(pointer) ⇒ Object



240
# File 'lib/crystalruby/types/type.rb', line 240

def self.each_child_address(pointer); end

.ffi_primitive_typeObject

For non-container ffi_primitive non-named types, just use the raw FFI type, as it’s much more efficient due to skipping Arc overhead.



253
254
255
# File 'lib/crystalruby/types/type.rb', line 253

def self.ffi_primitive_type
  respond_to?(:ffi_primitive) && anonymous? ? ffi_primitive : nil
end

.finalize(_memory) ⇒ Object



57
58
59
# File 'lib/crystalruby/types/type.rb', line 57

def self.finalize(_memory)
  ->(_) {}
end

.fixed_width?Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/crystalruby/types/type.rb', line 167

def self.fixed_width?
  false
end

.from_ffi_array_repr(value) ⇒ Object



191
192
193
# File 'lib/crystalruby/types/type.rb', line 191

def self.from_ffi_array_repr(value)
  anonymous? ? new(value).value : new(value)
end

.inner_typeObject



275
276
277
# File 'lib/crystalruby/types/type.rb', line 275

def self.inner_type
  inner_types.first
end

.inspectObject



295
296
297
# File 'lib/crystalruby/types/type.rb', line 295

def self.inspect
  type_expr
end

.inspect_nameObject



61
62
63
# File 'lib/crystalruby/types/type.rb', line 61

def self.inspect_name
  (name || "#{typename}").to_s.gsub(/^CrystalRuby::Types::[^::]+::/, "")
end

.named_type_exprObject



83
84
85
86
87
88
89
90
91
# File 'lib/crystalruby/types/type.rb', line 83

def self.named_type_expr
  if !inner_types
    "::#{name || typename}"
  elsif !inner_keys
    "::#{name || typename}(#{inner_types.map(&:named_type_expr).join(", ")})"
  else
    "::#{name || typename}(#{inner_keys.zip(inner_types).map { |k, v| "#{k}: #{v.named_type_expr}" }.join(", ")})"
  end
end

.native_type_exprObject



73
74
75
76
77
78
79
80
81
# File 'lib/crystalruby/types/type.rb', line 73

def self.native_type_expr
  if !inner_types
    "::#{typename}"
  elsif !inner_keys
    "::#{typename}(#{inner_types.map(&:native_type_expr).join(", ")})"
  else
    "::#{typename}(#{inner_keys.zip(inner_types).map { |k, v| "#{k}: #{v.native_type_expr}" }.join(", ")})"
  end
end

.nested_typesObject



131
132
133
# File 'lib/crystalruby/types/type.rb', line 131

def self.nested_types
  [self, *(inner_types || []).map(&:nested_types)].flatten.uniq
end

.numeric?Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/crystalruby/types/type.rb', line 155

def self.numeric?
  false
end

.pointer_to_crystal_type_conversion(expr) ⇒ Object



135
136
137
# File 'lib/crystalruby/types/type.rb', line 135

def self.pointer_to_crystal_type_conversion(expr)
  anonymous? ? "#{crystal_class_name}.new(#{expr}).native_decr" : "#{crystal_class_name}.new_decr(#{expr})"
end

.primitive?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/crystalruby/types/type.rb', line 159

def self.primitive?
  false
end

.subclass?(type) ⇒ Boolean

Returns:

  • (Boolean)


279
280
281
# File 'lib/crystalruby/types/type.rb', line 279

def self.subclass?(type)
  type.is_a?(Class) && type < Types::Type
end

.template_nameObject



143
144
145
# File 'lib/crystalruby/types/type.rb', line 143

def self.template_name
  typename || superclass.template_name
end

.type_defnObject



147
148
149
150
151
152
153
# File 'lib/crystalruby/types/type.rb', line 147

def self.type_defn
  unless Template.const_defined?(template_name) && Template.const_get(template_name).is_a?(Template::Renderer)
    raise "Template not found for #{template_name}"
  end

  Template.const_get(template_name).render(binding)
end

.type_digestObject



127
128
129
# File 'lib/crystalruby/types/type.rb', line 127

def self.type_digest
  Digest::MD5.hexdigest(native_type_expr.to_s)
end

.type_exprObject



283
284
285
286
287
288
289
290
291
292
293
# File 'lib/crystalruby/types/type.rb', line 283

def self.type_expr
  if !inner_types
    inspect_name
  elsif !anonymous?
    name
  elsif inner_keys
    "#{inspect_name}(#{inner_keys.zip(inner_types).map { |k, v| "#{k}: #{v.inspect}" }.join(", ")})"
  else
    "#{inspect_name}(#{inner_types.map(&:inspect).join(", ")})"
  end
end

.union_typesObject



65
66
67
# File 'lib/crystalruby/types/type.rb', line 65

def self.union_types
  [self]
end

.valid?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/crystalruby/types/type.rb', line 69

def self.valid?
  true
end

.valid_cast?(raw) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/crystalruby/types/type.rb', line 93

def self.valid_cast?(raw)
  raw.is_a?(self) || convert_if.any? { |type| raw.is_a?(type) }
end

.validate!(type) ⇒ Object



267
268
269
270
271
272
273
# File 'lib/crystalruby/types/type.rb', line 267

def self.validate!(type)
  unless type.is_a?(Class) && type.ancestors.include?(Types::Type)
    raise "Result #{type} is not a valid CrystalRuby type"
  end

  raise "Invalid type: #{type.error}" unless type.valid?
end

.variable_width?Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/crystalruby/types/type.rb', line 163

def self.variable_width?
  false
end

.|(other) ⇒ Object



261
262
263
264
265
# File 'lib/crystalruby/types/type.rb', line 261

def self.|(other)
  raise "Cannot union non-crystal type #{other}" unless other.is_a?(Class) && other.ancestors.include?(Type)

  CrystalRuby::Types::TaggedUnion(*union_types, *other.union_types)
end

Instance Method Details

#==(other) ⇒ Object



175
176
177
# File 'lib/crystalruby/types/type.rb', line 175

def ==(other)
  value(native: true) == (other.is_a?(Type) ? other.value(native: true) : other)
end

#coerce(other) ⇒ Object



183
184
185
# File 'lib/crystalruby/types/type.rb', line 183

def coerce(other)
  [other, value]
end

#deep_dupObject

Create a brand new copy of this object



200
201
202
# File 'lib/crystalruby/types/type.rb', line 200

def deep_dup
  self.class.new(native)
end

#dupObject

Create a new reference to this object.



205
206
207
# File 'lib/crystalruby/types/type.rb', line 205

def dup
  self.class.new(@memory)
end

#inner_valueObject



195
196
197
# File 'lib/crystalruby/types/type.rb', line 195

def inner_value
  @value
end

#inspectObject



187
188
189
# File 'lib/crystalruby/types/type.rb', line 187

def inspect
  value.inspect
end

#item_sizeObject



242
243
244
# File 'lib/crystalruby/types/type.rb', line 242

def item_size
  inner_types.map(&:memsize).sum
end

#nativeObject



123
124
125
# File 'lib/crystalruby/types/type.rb', line 123

def native
  value(native: true)
end

#nil?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/crystalruby/types/type.rb', line 179

def nil?
  value.nil?
end

#total_memsizeObject



246
247
248
# File 'lib/crystalruby/types/type.rb', line 246

def total_memsize
  memsize
end