Module: Libcall::TypeMap

Defined in:
lib/libcall/type_map.rb

Overview

Type mapping for FFI calls

Constant Summary collapse

MAP =

Map from string type names to FFI type symbols

{
  # Short type names (Rust-like)
  'i8' => :char,
  'u8' => :uchar,
  'i16' => :short,
  'u16' => :ushort,
  'i32' => :int,
  'u32' => :uint,
  'i64' => :long_long,
  'u64' => :ulong_long,
  'isize' => :long,
  'usize' => :ulong,
  'f32' => :float,
  'f64' => :double,
  # Pointer types
  'cstr' => :string,
  'ptr' => :voidp,
  'pointer' => :voidp,
  'void' => :void,
  # Common C type names
  'char' => :char,
  'uchar' => :uchar,
  'short' => :short,
  'ushort' => :ushort,
  'int' => :int,
  'uint' => :uint,
  'long' => :long,
  'ulong' => :ulong,
  'float' => :float,
  'double' => :double,
  # C-style pointer aliases
  'void*' => :voidp,
  'const void*' => :voidp,
  'const_void*' => :voidp,
  'const_voidp' => :voidp,
  # Underscored variants
  'unsigned_char' => :uchar,
  'unsigned_short' => :ushort,
  'unsigned_int' => :uint,
  'unsigned_long' => :ulong,
  'long_long' => :long_long,
  'unsigned_long_long' => :ulong_long,
  # Short aliases
  'unsigned' => :uint,
  'signed' => :int,
  # Extended type names (stdint-like)
  'int8' => :char,
  'uint8' => :uchar,
  'int16' => :short,
  'uint16' => :ushort,
  'int32' => :int,
  'uint32' => :uint,
  'int64' => :long_long,
  'uint64' => :ulong_long,
  'float32' => :float,
  'float64' => :double,
  # C99/C11 standard types with _t suffix
  'int8_t' => :char,
  'uint8_t' => :uchar,
  'int16_t' => :short,
  'uint16_t' => :ushort,
  'int32_t' => :int,
  'uint32_t' => :uint,
  'int64_t' => :long_long,
  'uint64_t' => :ulong_long,
  # Size and pointer-sized integers
  'size_t' => :ulong,
  'ssize_t' => :long,
  'intptr' => :long,
  'uintptr' => :ulong,
  'intptr_t' => :long,
  'uintptr_t' => :ulong,
  'ptrdiff_t' => :long,
  # Boolean
  'bool' => :int,
  # String aliases
  'str' => :string,
  'string' => :string
}.freeze
INTEGER_TYPES =

Integer type symbols

%i[
  int uint
  long ulong
  long_long ulong_long
  char uchar
  short ushort
].freeze
FLOAT_TYPES =

Floating point type symbols

%i[float double].freeze

Class Method Summary collapse

Class Method Details

.allocate_array(base_type, count) ⇒ Object

Allocate memory for an array of base type and count elements



231
232
233
# File 'lib/libcall/type_map.rb', line 231

def self.allocate_array(base_type, count)
  Fiddle::Pointer.malloc(sizeof(base_type) * count)
end

.allocate_output_pointer(type_sym) ⇒ Object

Allocate a pointer for output parameter



181
182
183
184
185
186
# File 'lib/libcall/type_map.rb', line 181

def self.allocate_output_pointer(type_sym)
  ptr = Fiddle::Pointer.malloc(sizeof(type_sym))
  # For out:string, we pass char**. Initialize inner pointer to NULL for safety.
  ptr[0, Fiddle::SIZEOF_VOIDP] = [0].pack('J') if type_sym == :string
  ptr
end

.float_type?(type_sym) ⇒ Boolean

Check if type symbol is a floating point type

Returns:

  • (Boolean)


112
113
114
# File 'lib/libcall/type_map.rb', line 112

def self.float_type?(type_sym)
  FLOAT_TYPES.include?(type_sym)
end

.integer_type?(type_sym) ⇒ Boolean

Check if type symbol is an integer type

Returns:

  • (Boolean)


107
108
109
# File 'lib/libcall/type_map.rb', line 107

def self.integer_type?(type_sym)
  INTEGER_TYPES.include?(type_sym)
end

.lookup(type_str) ⇒ Object

Look up FFI type symbol from string



102
103
104
# File 'lib/libcall/type_map.rb', line 102

def self.lookup(type_str)
  MAP[type_str]
end

.pack_template(base_type) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/libcall/type_map.rb', line 250

def self.pack_template(base_type)
  case base_type
  # Integer types (8-bit)
  when :char then 'c'
  when :uchar then 'C'
  # Integer types (16-bit)
  when :short then 's'
  when :ushort then 'S'
  # Integer types (32-bit)
  when :int then 'i'
  when :uint then 'I'
  # Integer types (platform-dependent)
  when :long then 'l!'
  when :ulong then 'L!'
  # Integer types (64-bit)
  when :long_long then 'q'
  when :ulong_long then 'Q'
  # Floating point types
  when :float then 'f'
  when :double then 'd'
  # Pointer types
  when :pointer, :voidp then 'J'
  # Special types
  when :size_t then (Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG ? 'L!' : 'Q')
  else
    raise Error, "Unsupported array base type: #{base_type}"
  end
end

.read_array(ptr, base_type, count) ⇒ Object



242
243
244
245
246
247
248
# File 'lib/libcall/type_map.rb', line 242

def self.read_array(ptr, base_type, count)
  return [] if count <= 0

  bytes = sizeof(base_type) * count
  raw = ptr[0, bytes]
  raw.unpack(pack_template(base_type) + count.to_s)
end

.read_output_pointer(ptr, type_sym) ⇒ Object

Read value from output pointer



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/libcall/type_map.rb', line 189

def self.read_output_pointer(ptr, type_sym)
  case type_sym
  # Integer types (8-bit)
  when :char then ptr[0, Fiddle::SIZEOF_CHAR].unpack1('c')
  when :uchar then ptr[0, Fiddle::SIZEOF_CHAR].unpack1('C')
  # Integer types (16-bit)
  when :short then ptr[0, Fiddle::SIZEOF_SHORT].unpack1('s')
  when :ushort then ptr[0, Fiddle::SIZEOF_SHORT].unpack1('S')
  # Integer types (32-bit)
  when :int then ptr[0, Fiddle::SIZEOF_INT].unpack1('i')
  when :uint then ptr[0, Fiddle::SIZEOF_INT].unpack1('I')
  # Integer types (platform-dependent)
  when :long then ptr[0, Fiddle::SIZEOF_LONG].unpack1('l!')
  when :ulong then ptr[0, Fiddle::SIZEOF_LONG].unpack1('L!')
  # Integer types (64-bit)
  when :long_long then ptr[0, Fiddle::SIZEOF_LONG_LONG].unpack1('q')
  when :ulong_long then ptr[0, Fiddle::SIZEOF_LONG_LONG].unpack1('Q')
  # Floating point types
  when :float then ptr[0, Fiddle::SIZEOF_FLOAT].unpack1('f')
  when :double then ptr[0, Fiddle::SIZEOF_DOUBLE].unpack1('d')
  # Pointer types
  when :voidp then format('0x%x', ptr[0, Fiddle::SIZEOF_VOIDP].unpack1('J'))
  when :string
    addr = ptr[0, Fiddle::SIZEOF_VOIDP].unpack1('J')
    return '(null)' if addr.zero?

    begin
      Fiddle::Pointer.new(addr).to_s
    rescue StandardError
      format('0x%x', addr)
    end
  else
    raise Error, "Cannot read output value for type: #{type_sym}"
  end
end

.read_scalar(ptr, type_sym) ⇒ Object

Read a single scalar value at address (helper for callbacks)



226
227
228
# File 'lib/libcall/type_map.rb', line 226

def self.read_scalar(ptr, type_sym)
  read_output_pointer(ptr, type_sym)
end

.sizeof(type_sym) ⇒ Object

Get the size in bytes for a type symbol



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/libcall/type_map.rb', line 156

def self.sizeof(type_sym)
  case type_sym
  # Integer types (8-bit)
  when :char, :uchar then Fiddle::SIZEOF_CHAR
  # Integer types (16-bit)
  when :short, :ushort then Fiddle::SIZEOF_SHORT
  # Integer types (32-bit)
  when :int, :uint then Fiddle::SIZEOF_INT
  # Integer types (platform-dependent)
  when :long, :ulong then Fiddle::SIZEOF_LONG
  # Integer types (64-bit)
  when :long_long, :ulong_long then Fiddle::SIZEOF_LONG_LONG
  # Floating point types
  when :float then Fiddle::SIZEOF_FLOAT
  when :double then Fiddle::SIZEOF_DOUBLE
  # Pointer types
  when :voidp, :pointer, :string then Fiddle::SIZEOF_VOIDP
  # Special types
  when :size_t then Fiddle::SIZEOF_SIZE_T
  else
    raise Error, "Cannot get size for type: #{type_sym}"
  end
end

.to_fiddle_type(type_sym) ⇒ Object

Convert type symbol to Fiddle type constant



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/libcall/type_map.rb', line 117

def self.to_fiddle_type(type_sym)
  # Array and output parameters are passed as pointers
  if type_sym.is_a?(Array)
    tag = type_sym.first
    return Fiddle::TYPE_VOIDP if %i[out array out_array].include?(tag)
  end

  # Callback function pointers are passed as void*
  return Fiddle::TYPE_VOIDP if type_sym == :callback

  case type_sym
  # Void type
  when :void then Fiddle::TYPE_VOID
  # Integer types (8-bit)
  when :char then Fiddle::TYPE_CHAR
  when :uchar then Fiddle::TYPE_UCHAR
  # Integer types (16-bit)
  when :short then Fiddle::TYPE_SHORT
  when :ushort then Fiddle::TYPE_USHORT
  # Integer types (32-bit)
  when :int, :uint then Fiddle::TYPE_INT
  # Integer types (platform-dependent)
  when :long, :ulong then Fiddle::TYPE_LONG
  # Integer types (64-bit)
  when :long_long, :ulong_long then Fiddle::TYPE_LONG_LONG
  # Floating point types
  when :float then Fiddle::TYPE_FLOAT
  when :double then Fiddle::TYPE_DOUBLE
  # Pointer types
  when :voidp, :pointer then Fiddle::TYPE_VOIDP
  when :string then Fiddle::TYPE_VOIDP
  # Special types
  when :size_t then Fiddle::TYPE_SIZE_T
  else
    raise Error, "Unknown Fiddle type: #{type_sym}"
  end
end

.write_array(ptr, base_type, values) ⇒ Object



235
236
237
238
239
240
# File 'lib/libcall/type_map.rb', line 235

def self.write_array(ptr, base_type, values)
  return if values.nil? || values.empty?

  bytes = sizeof(base_type) * values.length
  ptr[0, bytes] = values.pack(pack_template(base_type) + values.length.to_s)
end