Class: FFI::StructLayoutBuilder

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

Overview

Build a struct layout.

Constant Summary

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,
]

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)


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/ffi/struct_layout_builder.rb', line 118

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)


156
157
158
# File 'lib/ffi/struct_layout_builder.rb', line 156

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:



139
140
141
# File 'lib/ffi/struct_layout_builder.rb', line 139

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)


146
147
148
# File 'lib/ffi/struct_layout_builder.rb', line 146

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)


176
177
178
# File 'lib/ffi/struct_layout_builder.rb', line 176

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

#buildStructLayout

Build and return the struct layout.

Returns:



162
163
164
165
166
167
168
169
# File 'lib/ffi/struct_layout_builder.rb', line 162

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:



182
183
184
185
186
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
# File 'lib/ffi/struct_layout_builder.rb', line 182

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

    Set alignment and packed attributes to packed.

    Parameters:

    • packed (Fixnum)

    Returns:

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

    Set packed attribute.

    Parameters:

    • packed

    Returns:

    • (0, 1)


84
85
86
87
88
89
90
91
# File 'lib/ffi/struct_layout_builder.rb', line 84

def packed=(packed)
  if packed.is_a?(Fixnum)
    @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)


71
72
73
# File 'lib/ffi/struct_layout_builder.rb', line 71

def union?
  @union
end