类 Fiddle::CStructEntity

指向 C 结构的指针

公有类方法

alignment(types) 点击切换源代码
# File ext/fiddle/lib/fiddle/struct.rb, line 277
def CStructEntity.alignment(types)
  max = 1
  types.each do |type, count = 1|
    if type.respond_to?(:entity_class)
      n = type.alignment
    else
      n = ALIGN_MAP[type]
    end
    max = n if n > max
  end
  max
end
malloc(types, func = nil, size = size(types)) { |struct| ... } 点击切换源代码

使用提供的 types 分配一个 C 结构。

有关内存管理问题,请参阅 Fiddle::Pointer.malloc

调用超类方法 Fiddle::Pointer::malloc
# File ext/fiddle/lib/fiddle/struct.rb, line 293
def CStructEntity.malloc(types, func = nil, size = size(types), &block)
  if block_given?
    super(size, func) do |struct|
      struct.set_ctypes types
      yield struct
    end
  else
    struct = super(size, func)
    struct.set_ctypes types
    struct
  end
end
new(addr, types, func = nil) 点击切换源代码

将 C 指针 addr 包装为具有给定 types 的 C 结构。

当实例被垃圾回收时,将调用 C 函数 func

另请参阅 Fiddle::Pointer.new

调用超类方法 Fiddle::Pointer::new
# File ext/fiddle/lib/fiddle/struct.rb, line 340
def initialize(addr, types, func = nil)
  if func && addr.is_a?(Pointer) && addr.free
    raise ArgumentError, 'free function specified on both underlying struct Pointer and when creating a CStructEntity - who do you want to free this?'
  end
  set_ctypes(types)
  super(addr, @size, func)
end
size(types) 点击切换源代码

返回给定 types 的打包大小的偏移量。

Fiddle::CStructEntity.size(
  [ Fiddle::TYPE_DOUBLE,
    Fiddle::TYPE_INT,
    Fiddle::TYPE_CHAR,
    Fiddle::TYPE_VOIDP ]) #=> 24
# File ext/fiddle/lib/fiddle/struct.rb, line 313
def CStructEntity.size(types)
  offset = 0

  max_align = types.map { |type, count = 1|
    last_offset = offset

    if type.respond_to?(:entity_class)
      align = type.alignment
      type_size = type.size
    else
      align = PackInfo::ALIGN_MAP[type]
      type_size = PackInfo::SIZE_MAP[type]
    end
    offset = PackInfo.align(last_offset, align) +
             (type_size * count)

    align
  }.max

  PackInfo.align(offset, max_align)
end

公有实例方法

[](*args) 点击切换源代码

如果只指定一个参数,则获取结构成员 name。如果指定两个参数,第一个参数是偏移量,第二个参数是长度,此方法将返回从 offset 开始的 length 字节的字符串。

示例

my_struct = struct(['int id']).malloc
my_struct.id = 1
my_struct['id'] # => 1
my_struct[0, 4] # => "\x01\x00\x00\x00".b
调用超类方法 Fiddle::Pointer::[]
# File ext/fiddle/lib/fiddle/struct.rb, line 413
def [](*args)
  return super(*args) if args.size > 1
  name = args[0]
  idx = @members.index(name)
  if( idx.nil? )
    raise(ArgumentError, "no such member: #{name}")
  end
  ty = @ctypes[idx]
  if( ty.is_a?(Array) )
    if ty.first.respond_to?(:entity_class)
      return @nested_structs[name]
    else
      r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
    end
  elsif ty.respond_to?(:entity_class)
    return @nested_structs[name]
  else
    r = super(@offset[idx], SIZE_MAP[ty.abs])
  end
  packer = Packer.new([ty])
  val = packer.unpack([r])
  case ty
  when Array
    case ty[0]
    when TYPE_VOIDP
      val = val.collect{|v| Pointer.new(v)}
    end
  when TYPE_VOIDP
    val = Pointer.new(val[0])
  else
    val = val[0]
  end
  if( ty.is_a?(Integer) && (ty < 0) )
    return unsigned_value(val, ty)
  elsif( ty.is_a?(Array) && (ty[0] < 0) )
    return StructArray.new(self + @offset[idx], ty[0], val)
  else
    return val
  end
end
[]=(*args) 点击切换源代码

Set 结构成员 name,值为 val。如果指定更多参数,则将字节字符串写入给定 offsetlength 处的内存。

示例

my_struct = struct(['int id']).malloc
my_struct['id'] = 1
my_struct[0, 4] = "\x01\x00\x00\x00".b
my_struct.id # => 1
调用超类方法 Fiddle::Pointer#[]=
# File ext/fiddle/lib/fiddle/struct.rb, line 465
def []=(*args)
  return super(*args) if args.size > 2
  name, val = *args
  name = name.to_s if name.is_a?(Symbol)
  nested_struct = @nested_structs[name]
  if nested_struct
    if nested_struct.is_a?(StructArray)
      if val.nil?
        nested_struct.each do |s|
          s.replace(nil)
        end
      else
        val.each_with_index do |v, i|
          nested_struct[i] = v
        end
      end
    else
      nested_struct.replace(val)
    end
    return val
  end
  idx = @members.index(name)
  if( idx.nil? )
    raise(ArgumentError, "no such member: #{name}")
  end
  ty  = @ctypes[idx]
  packer = Packer.new([ty])
  val = wrap_arg(val, ty, [])
  buff = packer.pack([val].flatten())
  super(@offset[idx], buff.size, buff)
  if( ty.is_a?(Integer) && (ty < 0) )
    return unsigned_value(val, ty)
  elsif( ty.is_a?(Array) && (ty[0] < 0) )
    return val.collect{|v| unsigned_value(v,ty[0])}
  else
    return val
  end
end
assign_names(成员) 单击以切换源

设置此 C 结构中成员的名称

# File ext/fiddle/lib/fiddle/struct.rb, line 349
def assign_names(members)
  @members = []
  @nested_structs = {}
  members.each_with_index do |member, index|
    if member.is_a?(Array) # nested struct
      member_name = member[0]
      struct_type, struct_count = @ctypes[index]
      if struct_count.nil?
        struct = struct_type.new(to_i + @offset[index])
      else
        structs = struct_count.times.map do |i|
          struct_type.new(to_i + @offset[index] + i * struct_type.size)
        end
        struct = StructArray.new(to_i + @offset[index],
                                 struct_type,
                                 structs)
      end
      @nested_structs[member_name] = struct
    else
      member_name = member
    end
    @members << member_name
  end
end
set_ctypes(类型) 单击以切换源

计算结构中给定类型的偏移量和大小。

# File ext/fiddle/lib/fiddle/struct.rb, line 375
def set_ctypes(types)
  @ctypes = types
  @offset = []
  offset = 0

  max_align = types.map { |type, count = 1|
    orig_offset = offset
    if type.respond_to?(:entity_class)
      align = type.alignment
      type_size = type.size
    else
      align = ALIGN_MAP[type]
      type_size = SIZE_MAP[type]
    end
    offset = PackInfo.align(orig_offset, align)

    @offset << offset

    offset += (type_size * count)

    align
  }.max

  @size = PackInfo.align(offset, max_align)
end