Module: Fiddle::CStructBuilder

Defined in:
lib/fiddle/struct.rb

Overview

Used to construct C classes (CUnion, CStruct, etc)

Fiddle::Importer#struct and Fiddle::Importer#union wrap this functionality in an easy-to-use manner.

Class Method Summary collapse

Class Method Details

.create(klass, types, members) ⇒ Object

Construct a new class given a C:

  • class klass (CUnion, CStruct, or other that provide an #entity_class)

  • types (Fiddle::TYPE_INT, Fiddle::TYPE_SIZE_T, etc., see the C types constants)

  • corresponding members

Fiddle::Importer#struct and Fiddle::Importer#union wrap this functionality in an easy-to-use manner.

Examples:

require 'fiddle/struct'
require 'fiddle/cparser'

include Fiddle::CParser

types, members = parse_struct_signature(['int i','char c'])

MyStruct = Fiddle::CStructBuilder.create(Fiddle::CUnion, types, members)

MyStruct.malloc(Fiddle::RUBY_FREE) do |obj|
  ...
end

obj = MyStruct.malloc(Fiddle::RUBY_FREE)
begin
  ...
ensure
  obj.call_free
end

obj = MyStruct.malloc
begin
  ...
ensure
  Fiddle.free obj.to_ptr
end


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/fiddle/struct.rb', line 215

def create(klass, types, members)
  new_class = Class.new(klass){
    define_method(:initialize){|addr, func = nil|
      if addr.is_a?(self.class.entity_class)
        @entity = addr
      else
        @entity = self.class.entity_class.new(addr, types, func)
      end
      @entity.assign_names(members)
    }
    define_method(:[]) { |*args| @entity.send(:[], *args) }
    define_method(:[]=) { |*args| @entity.send(:[]=, *args) }
    define_method(:to_ptr){ @entity }
    define_method(:to_i){ @entity.to_i }
    define_singleton_method(:types) { types }
    define_singleton_method(:members) { members }

    # Return the offset of a struct member given its name.
    # For example:
    #
    #     MyStruct = struct [
    #       "int64_t i",
    #       "char c",
    #     ]
    #
    #     MyStruct.offsetof("i") # => 0
    #     MyStruct.offsetof("c") # => 8
    #
    define_singleton_method(:offsetof) { |name|
      klass.offsetof(name, members, types)
    }
    members.each{|name|
      name = name[0] if name.is_a?(Array) # name is a nested struct
      next if method_defined?(name)
      define_method(name){ @entity[name] }
      define_method(name + "="){|val| @entity[name] = val }
    }
    entity_class = klass.entity_class
    alignment = entity_class.alignment(types)
    size = entity_class.size(types)
    define_singleton_method(:alignment) { alignment }
    define_singleton_method(:size) { size }
    define_singleton_method(:malloc) do |func=nil, &block|
      if block
        entity_class.malloc(types, func, size) do |entity|
          block.call(new(entity))
        end
      else
        new(entity_class.malloc(types, func, size))
      end
    end
  }
  return new_class
end