Module: Vigilem::FFI::Utils

Extended by:
Utils
Included in:
Utils
Defined in:
lib/vigilem/ffi/utils.rb,
lib/vigilem/ffi/utils/struct.rb

Overview

utilities for FFI

Defined Under Namespace

Modules: Struct

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._struct_to_h(struct, current = 1, limit = nil) ⇒ Hash || Struct

Parameters:

  • struct (#members, #values)
  • limit (Integer || NilClass) (defaults to: nil)

Returns:



228
229
230
231
232
233
234
# File 'lib/vigilem/ffi/utils.rb', line 228

def _struct_to_h(struct, current=1, limit=nil)
  if limit.nil? or limit <= current
    Hash[struct.members.zip(struct.values.map {|val| is_a_struct?(val) ? _struct_to_h(val) : val } )]
  else
    struct
  end
end

Instance Method Details

#_struct_bulk_assign(struct, field, attr_name, vals) ⇒ Object

TODO:

unions don’t need know the member name, the space taken up is the same

TODO:

refactor me

Parameters:

  • struct (::FFI::Struct)
  • field (::FFI::StructLayout::Field)
  • attr_name (Symbol)
  • vals (Array || Hash)

Returns:



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/vigilem/ffi/utils.rb', line 178

def _struct_bulk_assign(struct, field, attr_name, vals)
  # struct.type.struct_class, why use field?
  #if is_a_struct?(struct.type)
  if is_a_struct?(field)
    if is_a_struct?(frst = vals.first) or frst.is_a? ::FFI::Union
      struct[attr_name] = vals.shift
    else
      ptr_offset = struct.offsets.assoc(attr_name).last
      struct_obj = if (struct_klass = field.type.struct_class) <= VFFIStruct
                    struct_klass.new(ptr_offset)
                  else
                    struct_klass.new
                  end
      struct[attr_name] = struct_bulk_assign(struct_obj, vals.shift)
    end
  else
    raise ArgumentError, "Arity mismatch: complex type `#{struct.inspect}' does not match argument `#{vals.inspect}'" unless vals.respond_to? :shift
    struct[attr_name] = vals.shift
  end
end

#add_int_typedef(pointer, type, value) ⇒ Object

Returns pointer.

Parameters:

  • pointer (::FFI::Pointer)
  • type (Symbol || ::FFI::Type::Builtin)
  • value

Returns:

  • pointer



119
120
121
# File 'lib/vigilem/ffi/utils.rb', line 119

def add_int_typedef(pointer, type, value)
  replace_typedef(pointer, type, (value + self.read_typedef(pointer, type)))
end

#ary_of_type(type, type_size, pointer, len = -1)) ⇒ Array

converts a pointer to an ary of ary_type

Parameters:

  • type
  • type_size, (Fixnum)

    this is given because a ::from_string has type_size of 1

  • pointer (FFI::Pointer)

Returns:

  • (Array)

    of type



212
213
214
215
216
217
218
219
# File 'lib/vigilem/ffi/utils.rb', line 212

def ary_of_type(type, type_size, pointer, len=-1)
  if type.is_a? Class and type <= ::FFI::Struct
    # @todo slice is supposed to return new a pointer, when atype.type_size == pointer.type_size does this return the old pointer?
    0.upto((pointer.size/type_size) - 1).map {|n| type.new(pointer.slice(n * type_size, type_size).dup) }
  else
    ::Vigilem::FFI::Utils.read_array_typedef(pointer, type, ptr_capacity(pointer))
  end
end

#bytes_to_structs(struct_class, str_bytes) ⇒ Array<FFI::Struct>

Parameters:

  • struct_class (Class)
  • str_bytes (String)

Returns:



203
204
205
# File 'lib/vigilem/ffi/utils.rb', line 203

def bytes_to_structs(struct_class, str_bytes)
  ary_of_type(struct_class, struct_class.size, ::FFI::MemoryPointer.from_string(str_bytes))
end

#get_builtin_type_name(type) ⇒ Symbol Also known as: get_native_type_name

gets the FFI::Type::Builtin a type

Parameters:

  • type (Symbol || ::FFI::Type::Builtin)

Returns:

  • (Symbol)

    the builtin type name

Raises:

  • (TypeError)


17
18
19
20
21
# File 'lib/vigilem/ffi/utils.rb', line 17

def get_builtin_type_name(type)
  builtin = ::FFI.find_type(type) || type
  raise TypeError, "unable to resolve type '#{type}'" unless builtin.is_a? ::FFI::Type::Builtin
  (nt = ::FFI::NativeType).constants.find {|const| nt.const_get(const) == builtin }.downcase
end

#is_a_struct?(obj) ⇒ TrueClass || FalseClass

Parameters:

  • obj (#type)

Returns:

  • (TrueClass || FalseClass)


36
37
38
# File 'lib/vigilem/ffi/utils.rb', line 36

def is_a_struct?(obj)
  [::FFI::Struct, ::FFI::StructByValue, ::FFI::StructByReference].any? {|struct_klass| obj.is_a?(struct_klass) or obj.respond(:type).is_a? struct_klass }
end

#ptr_capacity(pointer) ⇒ Integer

TODO:

this is a problem, like XOpenDisplay, the ptr returned

maybe huge, but that;s not the size of the object in the pointer

Parameters:

  • pointer (Pointer)

Returns:

  • (Integer)


29
30
31
# File 'lib/vigilem/ffi/utils.rb', line 29

def ptr_capacity(pointer)
  pointer.size/pointer.type_size
end

#put_array_typedef(pointer, type, value, offset = 0) ⇒ Object

Returns pointer.

Parameters:

  • pointer (::FFI::Pointer)
  • type (String)
  • value (Array)
  • offset (Integer) (defaults to: 0)

Returns:

  • pointer



101
102
103
# File 'lib/vigilem/ffi/utils.rb', line 101

def put_array_typedef(pointer, type, value, offset=0)
  pointer.__send__(:"put_array_of_#{get_builtin_type_name(type) }", offset, [*value])
end

#put_typedef(pointer, type, value, offset = 0) ⇒ ::FFI::Pointer

Returns pointer.

Parameters:

  • pointer (::FFI::Pointer)
  • type (String)
  • value
  • offset (Integer) (defaults to: 0)

Returns:



91
92
93
# File 'lib/vigilem/ffi/utils.rb', line 91

def put_typedef(pointer, type, value, offset=0)
  pointer.__send__(:"put_#{get_builtin_type_name(type) }", offset, value)
end

#read_array_of_structs(pointer, struct_class, num = nil) ⇒ Array

Parameters:

  • pointer (::FFI::Pointer)
  • struct_class (Class)
  • num (Integer) (defaults to: nil)

Returns:

  • (Array)


54
55
56
# File 'lib/vigilem/ffi/utils.rb', line 54

def read_array_of_structs(pointer, struct_class, num=nil)
  1.upto(num||pointer.type_size/struct_class.size).map { struct_class.new(pointer) }
end

#read_array_typedef(pointer, type, num = 1) ⇒ Array

Parameters:

  • pointer (::FFI::Pointer)
  • type (Symbol || ::FFI::Type::Builtin)
  • num (Integer) (defaults to: 1)

Returns:

  • (Array)


81
82
83
# File 'lib/vigilem/ffi/utils.rb', line 81

def read_array_typedef(pointer, type, num=1)
  pointer.__send__(:"read_array_of_#{get_builtin_type_name(type) }", num)
end

#read_typedef(pointer, type) ⇒ Object

Returns value from pointer.

Parameters:

Returns:

  • value from pointer



72
73
74
# File 'lib/vigilem/ffi/utils.rb', line 72

def read_typedef(pointer, type)
  pointer.__send__(:"read_#{get_builtin_type_name(type) }")
end

#replace_typedef(pointer, type, value) ⇒ ::FFI::Pointer

Returns pointer.

Parameters:

  • pointer (::FFI::Pointer)
  • type (Symbol || ::FFI::Type::Builtin)
  • value

Returns:



110
111
112
# File 'lib/vigilem/ffi/utils.rb', line 110

def replace_typedef(pointer, type, value)
  put_typedef(pointer, type, value)
end

#struct_bulk_assign(struct, vals) ⇒ Object Also known as: from_array

TODO:

refactor me

assigns values to the struct

Parameters:

  • struct (::FFI::Struct)
  • vals (Array || Hash)

Returns:

  • struct



143
144
145
146
147
148
149
150
151
152
# File 'lib/vigilem/ffi/utils.rb', line 143

def struct_bulk_assign(struct, vals)
  if vals.is_a? Hash
    self.struct_bulk_assign_hash(struct, vals)
  else
    types(struct) do |fld|
      _struct_bulk_assign(struct, fld, fld.name, vals)
    end
  end
  struct
end

#struct_bulk_assign_hash(struct, hsh) ⇒ Object Also known as: from_hash

Returns struct.

Parameters:

  • struct (::FFI::Struct)
  • hsh (Hash)

Returns:

  • struct



160
161
162
163
164
165
166
167
# File 'lib/vigilem/ffi/utils.rb', line 160

def struct_bulk_assign_hash(struct, hsh)
  hsh.each do |key, value|
    the_field = struct.layout.fields.find {|fld| fld.name == key }
    raise "on #{struct.class} attr #{key} not found in #{struct.layout.fields.map(&:name)}" unless the_field
    _struct_bulk_assign(struct, the_field, key, [hsh[key]])
  end
  struct
end

#struct_to_h(struct, limit = nil) ⇒ Hash

converts struct to a Hash

Parameters:

  • struct (#members, #values)
  • limit (Integer || NilClass) (defaults to: nil)

Returns:

  • (Hash)


10
11
12
# File 'lib/vigilem/ffi/utils.rb', line 10

def struct_to_h(struct, limit=nil)
  Utils._struct_to_h(struct, limit)
end

#types(struct, &block) ⇒ Object

TODO:

needed?

Returns the type of the fields or the result of the block.

Parameters:

  • struct
  • block (Proc)

Returns:

  • the type of the fields or the result of the block



127
128
129
130
131
132
133
134
135
136
# File 'lib/vigilem/ffi/utils.rb', line 127

def types(struct, &block)
  struct = Support::Utils.get_class(struct) unless struct.respond_to? :layout
  struct.layout.fields.map do |field|
    if block
      yield field
    else
      field.type
    end
  end
end

#write_array_typedef(pointer, type, value) ⇒ ::FFI::Pointer

possible refactor ‘pointer.write_array_of_type(type, :“write_array_of_#{get_builtin_type_name(type) }”, [*value])`

Parameters:

  • pointer (::FFI::Pointer)
  • type (Symbol || ::FFI::Type::Builtin)
  • value (Array)

Returns:



64
65
66
# File 'lib/vigilem/ffi/utils.rb', line 64

def write_array_typedef(pointer, type, value)
  pointer.__send__(:"write_array_of_#{get_builtin_type_name(type) }", [*value])
end

#write_typedef(pointer, type, value) ⇒ ::FFI::Pointer

Returns pointer.

Parameters:

  • pointer (::FFI::Pointer)
  • type (Symbol || ::FFI::Type::Builtin)
  • value

Returns:



45
46
47
# File 'lib/vigilem/ffi/utils.rb', line 45

def write_typedef(pointer, type, value)
  pointer.__send__(:"write_#{get_builtin_type_name(type) }", value)
end