Class: FFI::StructLayoutBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/ffi/struct_layout_builder.rb

Overview

Build a struct layout.

Constant Summary collapse

NUMBER_TYPES =

List of number types

[
  Type::INT8,
  Type::UINT8,
  Type::INT16,
  Type::UINT16,
  Type::INT32,
  Type::UINT32,
  Type::LONG,
  Type::ULONG,
  Type::INT64,
  Type::UINT64,
  Type::FLOAT32,
  Type::FLOAT64,
  Type::LONGDOUBLE,
  Type::BOOL,
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeStructLayoutBuilder

Returns a new instance of StructLayoutBuilder.



39
40
41
42
43
44
45
46
# File 'lib/ffi/struct_layout_builder.rb', line 39

def initialize
  @size = 0
  @alignment = 1
  @min_alignment = 1
  @packed = false
  @union = false
  @fields = Array.new
end

Instance Attribute Details

#alignmentObject

Returns the value of attribute alignment.



37
38
39
# File 'lib/ffi/struct_layout_builder.rb', line 37

def alignment
  @alignment
end

#sizeObject

Returns the value of attribute size.



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

def size
  @size
end

Instance Method Details

#add(name, type, offset = nil) ⇒ self

Note:

Setting offset to nil or -1 is equivalent to 0.

Add a field to the builder.

Parameters:

Returns:

  • (self)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/ffi/struct_layout_builder.rb', line 123

def add(name, type, offset = nil)

  if offset.nil? || offset == -1
    offset = @union ? 0 : align(@size, @packed ? [ @packed, type.alignment ].min : [ @min_alignment, type.alignment ].max)
  end

  #
  # If a FFI::Type type was passed in as the field arg, try and convert to a StructLayout::Field instance
  #
  field = type.is_a?(StructLayout::Field) ? type : field_for_type(name, offset, type)
  @fields << field
  @alignment = [ @alignment, field.alignment ].max unless @packed
  @size = [ @size, field.size + (@union ? 0 : field.offset) ].max

  return self
end

#add_array(name, type, count, offset = nil) ⇒ self

Add an array as a field to the builder.

Parameters:

  • count (Numeric)

    array length

  • name (String, Symbol)

    name of the field

  • type (Array, DataConverter, Struct, StructLayout::Field, Symbol, Type)

    type of the field

  • offset (Numeric, nil) (defaults to: nil)

Returns:

  • (self)


161
162
163
# File 'lib/ffi/struct_layout_builder.rb', line 161

def add_array(name, type, count, offset = nil)
  add(name, Type::Array.new(type, count), offset)
end

#add_field(name, type, offset = nil) ⇒ self

Same as #add.

Parameters:

Returns:

  • (self)

See Also:



144
145
146
# File 'lib/ffi/struct_layout_builder.rb', line 144

def add_field(name, type, offset = nil)
  add(name, type, offset)
end

#add_struct(name, type, offset = nil) ⇒ self

Add a struct as a field to the builder.

Parameters:

Returns:

  • (self)


151
152
153
# File 'lib/ffi/struct_layout_builder.rb', line 151

def add_struct(name, type, offset = nil)
  add(name, Type::Struct.new(type), offset)
end

#align(offset, align) ⇒ Numeric (private)

Parameters:

  • offset (Numeric)
  • align (Numeric)

Returns:

  • (Numeric)


181
182
183
# File 'lib/ffi/struct_layout_builder.rb', line 181

def align(offset, align)
  align + ((offset - 1) & ~(align - 1));
end

#buildStructLayout

Build and return the struct layout.

Returns:



167
168
169
170
171
172
173
174
# File 'lib/ffi/struct_layout_builder.rb', line 167

def build
  # Add tail padding if the struct is not packed
  size = @packed ? @size : align(@size, @alignment)

  layout = StructLayout.new(@fields, size, @alignment)
  layout.__union! if @union
  layout
end

#field_for_type(name, offset, type) ⇒ StructLayout::Field (private)

Parameters:

Returns:



187
188
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
224
# File 'lib/ffi/struct_layout_builder.rb', line 187

def field_for_type(name, offset, type)
  field_class = case
  when type.is_a?(Type::Function)
    StructLayout::Function

  when type.is_a?(Type::Struct)
    StructLayout::InnerStruct

  when type.is_a?(Type::Array)
    StructLayout::Array

  when type.is_a?(FFI::Enum)
    StructLayout::Enum

  when NUMBER_TYPES.include?(type)
    StructLayout::Number

  when type == Type::POINTER
    StructLayout::Pointer

  when type == Type::STRING
    StructLayout::String

  when type.is_a?(Class) && type < StructLayout::Field
    type

  when type.is_a?(DataConverter)
    return StructLayout::Mapped.new(name, offset, Type::Mapped.new(type), field_for_type(name, offset, type.native_type))

  when type.is_a?(Type::Mapped)
    return StructLayout::Mapped.new(name, offset, type, field_for_type(name, offset, type.native_type))

  else
    raise TypeError, "invalid struct field type #{type.inspect}"
  end

  field_class.new(name, offset, type)
end

#packed=(packed) ⇒ packed #packed=(packed) ⇒ 0, 1

Set packed attribute

Overloads:

  • #packed=(packed) ⇒ packed

    packed.

    Parameters:

    • packed (Fixnum)

    Returns:

    • (packed)
  • #packed=(packed) ⇒ 0, 1

    Parameters:

    • packed

    Returns:

    • (0, 1)


89
90
91
92
93
94
95
96
# File 'lib/ffi/struct_layout_builder.rb', line 89

def packed=(packed)
  if packed.is_a?(0.class)
    @alignment = packed
    @packed = packed
  else
    @packed = packed ? 1 : 0
  end
end

#union=(is_union) ⇒ is_union

Set union attribute. Set to true to build a Union instead of a FFI::Struct.

Parameters:

  • is_union (Boolean)

Returns:

  • (is_union)


65
66
67
# File 'lib/ffi/struct_layout_builder.rb', line 65

def union=(is_union)
  @union = is_union
end

#union?Boolean

Building a Union or a FFI::Struct ?

Returns:

  • (Boolean)


73
74
75
# File 'lib/ffi/struct_layout_builder.rb', line 73

def union?
  @union
end